mirror of
https://github.com/Qortal/qortal.git
synced 2025-04-23 19:37:51 +00:00
Added _PRIVATE
services, to allow for publishing/validation of encrypted data.
New additions: QCHAT_ATTACHMENT_PRIVATE ATTACHMENT_PRIVATE FILE_PRIVATE IMAGE_PRIVATE VIDEO_PRIVATE AUDIO_PRIVATE VOICE_PRIVATE DOCUMENT_PRIVATE MAIL_PRIVATE MESSAGE_PRIVATE
This commit is contained in:
parent
1a5e3b4fb1
commit
c172a5764b
@ -9,7 +9,6 @@ import org.qortal.utils.FilesystemUtils;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -20,9 +19,9 @@ import static java.util.Arrays.stream;
|
|||||||
import static java.util.stream.Collectors.toMap;
|
import static java.util.stream.Collectors.toMap;
|
||||||
|
|
||||||
public enum Service {
|
public enum Service {
|
||||||
AUTO_UPDATE(1, false, null, false, null),
|
AUTO_UPDATE(1, false, null, false, false, null),
|
||||||
ARBITRARY_DATA(100, false, null, false, null),
|
ARBITRARY_DATA(100, false, null, false, false, null),
|
||||||
QCHAT_ATTACHMENT(120, true, 1024*1024L, true, null) {
|
QCHAT_ATTACHMENT(120, true, 1024*1024L, true, false, null) {
|
||||||
@Override
|
@Override
|
||||||
public ValidationResult validate(Path path) throws IOException {
|
public ValidationResult validate(Path path) throws IOException {
|
||||||
ValidationResult superclassResult = super.validate(path);
|
ValidationResult superclassResult = super.validate(path);
|
||||||
@ -47,11 +46,14 @@ public enum Service {
|
|||||||
return ValidationResult.OK;
|
return ValidationResult.OK;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ATTACHMENT(130, false, null, true, null),
|
QCHAT_ATTACHMENT_PRIVATE(121, true, 1024*1024L, true, true, null),
|
||||||
FILE(140, false, null, true, null),
|
ATTACHMENT(130, false, 50*1024*1024L, true, false, null),
|
||||||
FILES(150, false, null, false, null),
|
ATTACHMENT_PRIVATE(131, true, 50*1024*1024L, true, true, null),
|
||||||
CHAIN_DATA(160, true, 239L, true, null),
|
FILE(140, false, null, true, false, null),
|
||||||
WEBSITE(200, true, null, false, null) {
|
FILE_PRIVATE(141, true, null, true, true, null),
|
||||||
|
FILES(150, false, null, false, false, null),
|
||||||
|
CHAIN_DATA(160, true, 239L, true, false, null),
|
||||||
|
WEBSITE(200, true, null, false, false, null) {
|
||||||
@Override
|
@Override
|
||||||
public ValidationResult validate(Path path) throws IOException {
|
public ValidationResult validate(Path path) throws IOException {
|
||||||
ValidationResult superclassResult = super.validate(path);
|
ValidationResult superclassResult = super.validate(path);
|
||||||
@ -73,25 +75,30 @@ public enum Service {
|
|||||||
return ValidationResult.MISSING_INDEX_FILE;
|
return ValidationResult.MISSING_INDEX_FILE;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GIT_REPOSITORY(300, false, null, false, null),
|
GIT_REPOSITORY(300, false, null, false, false, null),
|
||||||
IMAGE(400, true, 10*1024*1024L, true, null),
|
IMAGE(400, true, 10*1024*1024L, true, false, null),
|
||||||
THUMBNAIL(410, true, 500*1024L, true, null),
|
IMAGE_PRIVATE(401, true, 10*1024*1024L, true, true, null),
|
||||||
QCHAT_IMAGE(420, true, 500*1024L, true, null),
|
THUMBNAIL(410, true, 500*1024L, true, false, null),
|
||||||
VIDEO(500, false, null, true, null),
|
QCHAT_IMAGE(420, true, 500*1024L, true, false, null),
|
||||||
AUDIO(600, false, null, true, null),
|
VIDEO(500, false, null, true, false, null),
|
||||||
QCHAT_AUDIO(610, true, 10*1024*1024L, true, null),
|
VIDEO_PRIVATE(501, true, null, true, true, null),
|
||||||
QCHAT_VOICE(620, true, 10*1024*1024L, true, null),
|
AUDIO(600, false, null, true, false, null),
|
||||||
VOICE(630, true, 10*1024*1024L, true, null),
|
AUDIO_PRIVATE(601, true, null, true, true, null),
|
||||||
PODCAST(640, false, null, true, null),
|
QCHAT_AUDIO(610, true, 10*1024*1024L, true, false, null),
|
||||||
BLOG(700, false, null, false, null),
|
QCHAT_VOICE(620, true, 10*1024*1024L, true, false, null),
|
||||||
BLOG_POST(777, false, null, true, null),
|
VOICE(630, true, 10*1024*1024L, true, false, null),
|
||||||
BLOG_COMMENT(778, true, 500*1024L, true, null),
|
VOICE_PRIVATE(631, true, 10*1024*1024L, true, true, null),
|
||||||
DOCUMENT(800, false, null, true, null),
|
PODCAST(640, false, null, true, false, null),
|
||||||
LIST(900, true, null, true, null),
|
BLOG(700, false, null, false, false, null),
|
||||||
PLAYLIST(910, true, null, true, null),
|
BLOG_POST(777, false, null, true, false, null),
|
||||||
APP(1000, true, 50*1024*1024L, false, null),
|
BLOG_COMMENT(778, true, 500*1024L, true, false, null),
|
||||||
METADATA(1100, false, null, true, null),
|
DOCUMENT(800, false, null, true, false, null),
|
||||||
JSON(1110, true, 25*1024L, true, null) {
|
DOCUMENT_PRIVATE(801, true, null, true, true, null),
|
||||||
|
LIST(900, true, null, true, false, null),
|
||||||
|
PLAYLIST(910, true, null, true, false, null),
|
||||||
|
APP(1000, true, 50*1024*1024L, false, false, null),
|
||||||
|
METADATA(1100, false, null, true, false, null),
|
||||||
|
JSON(1110, true, 25*1024L, true, false, null) {
|
||||||
@Override
|
@Override
|
||||||
public ValidationResult validate(Path path) throws IOException {
|
public ValidationResult validate(Path path) throws IOException {
|
||||||
ValidationResult superclassResult = super.validate(path);
|
ValidationResult superclassResult = super.validate(path);
|
||||||
@ -110,7 +117,7 @@ public enum Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GIF_REPOSITORY(1200, true, 25*1024*1024L, false, null) {
|
GIF_REPOSITORY(1200, true, 25*1024*1024L, false, false, null) {
|
||||||
@Override
|
@Override
|
||||||
public ValidationResult validate(Path path) throws IOException {
|
public ValidationResult validate(Path path) throws IOException {
|
||||||
ValidationResult superclassResult = super.validate(path);
|
ValidationResult superclassResult = super.validate(path);
|
||||||
@ -146,27 +153,30 @@ public enum Service {
|
|||||||
return ValidationResult.OK;
|
return ValidationResult.OK;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
STORE(1300, false, null, true, null),
|
STORE(1300, false, null, true, false, null),
|
||||||
PRODUCT(1310, false, null, true, null),
|
PRODUCT(1310, false, null, true, false, null),
|
||||||
OFFER(1330, false, null, true, null),
|
OFFER(1330, false, null, true, false, null),
|
||||||
COUPON(1340, false, null, true, null),
|
COUPON(1340, false, null, true, false, null),
|
||||||
CODE(1400, false, null, true, null),
|
CODE(1400, false, null, true, false, null),
|
||||||
PLUGIN(1410, false, null, true, null),
|
PLUGIN(1410, false, null, true, false, null),
|
||||||
EXTENSION(1420, false, null, true, null),
|
EXTENSION(1420, false, null, true, false, null),
|
||||||
GAME(1500, false, null, false, null),
|
GAME(1500, false, null, false, false, null),
|
||||||
ITEM(1510, false, null, true, null),
|
ITEM(1510, false, null, true, false, null),
|
||||||
NFT(1600, false, null, true, null),
|
NFT(1600, false, null, true, false, null),
|
||||||
DATABASE(1700, false, null, false, null),
|
DATABASE(1700, false, null, false, false, null),
|
||||||
SNAPSHOT(1710, false, null, false, null),
|
SNAPSHOT(1710, false, null, false, false, null),
|
||||||
COMMENT(1800, true, 500*1024L, true, null),
|
COMMENT(1800, true, 500*1024L, true, false, null),
|
||||||
CHAIN_COMMENT(1810, true, 239L, true, null),
|
CHAIN_COMMENT(1810, true, 239L, true, false, null),
|
||||||
MAIL(1900, true, 1024*1024L, true, null),
|
MAIL(1900, true, 1024*1024L, true, false, null),
|
||||||
MESSAGE(1910, true, 1024*1024L, true, null);
|
MAIL_PRIVATE(1901, true, 1024*1024L, true, true, null),
|
||||||
|
MESSAGE(1910, true, 1024*1024L, true, false, null),
|
||||||
|
MESSAGE_PRIVATE(1911, true, 1024*1024L, true, true, null);
|
||||||
|
|
||||||
public final int value;
|
public final int value;
|
||||||
private final boolean requiresValidation;
|
private final boolean requiresValidation;
|
||||||
private final Long maxSize;
|
private final Long maxSize;
|
||||||
private final boolean single;
|
private final boolean single;
|
||||||
|
private final boolean isPrivate;
|
||||||
private final List<String> requiredKeys;
|
private final List<String> requiredKeys;
|
||||||
|
|
||||||
private static final Map<Integer, Service> map = stream(Service.values())
|
private static final Map<Integer, Service> map = stream(Service.values())
|
||||||
@ -175,11 +185,14 @@ public enum Service {
|
|||||||
// For JSON validation
|
// For JSON validation
|
||||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
Service(int value, boolean requiresValidation, Long maxSize, boolean single, List<String> requiredKeys) {
|
private static final String encryptedDataPrefix = "qortalEncryptedData";
|
||||||
|
|
||||||
|
Service(int value, boolean requiresValidation, Long maxSize, boolean single, boolean isPrivate, List<String> requiredKeys) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.requiresValidation = requiresValidation;
|
this.requiresValidation = requiresValidation;
|
||||||
this.maxSize = maxSize;
|
this.maxSize = maxSize;
|
||||||
this.single = single;
|
this.single = single;
|
||||||
|
this.isPrivate = isPrivate;
|
||||||
this.requiredKeys = requiredKeys;
|
this.requiredKeys = requiredKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,6 +216,17 @@ public enum Service {
|
|||||||
return ValidationResult.INVALID_FILE_COUNT;
|
return ValidationResult.INVALID_FILE_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate private data for single file resources
|
||||||
|
if (this.single) {
|
||||||
|
String dataString = new String(data, StandardCharsets.UTF_8);
|
||||||
|
if (this.isPrivate && !dataString.startsWith(encryptedDataPrefix)) {
|
||||||
|
return ValidationResult.DATA_NOT_ENCRYPTED;
|
||||||
|
}
|
||||||
|
if (!this.isPrivate && dataString.startsWith(encryptedDataPrefix)) {
|
||||||
|
return ValidationResult.DATA_ENCRYPTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Validate required keys if needed
|
// Validate required keys if needed
|
||||||
if (this.requiredKeys != null) {
|
if (this.requiredKeys != null) {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
@ -221,7 +245,8 @@ public enum Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isValidationRequired() {
|
public boolean isValidationRequired() {
|
||||||
return this.requiresValidation;
|
// We must always validate single file resources, to ensure they are actually a single file
|
||||||
|
return this.requiresValidation || this.single;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Service valueOf(int value) {
|
public static Service valueOf(int value) {
|
||||||
@ -242,7 +267,9 @@ public enum Service {
|
|||||||
INVALID_FILE_EXTENSION(6),
|
INVALID_FILE_EXTENSION(6),
|
||||||
MISSING_DATA(7),
|
MISSING_DATA(7),
|
||||||
INVALID_FILE_COUNT(8),
|
INVALID_FILE_COUNT(8),
|
||||||
INVALID_CONTENT(9);
|
INVALID_CONTENT(9),
|
||||||
|
DATA_NOT_ENCRYPTED(10),
|
||||||
|
DATA_ENCRYPTED(10);
|
||||||
|
|
||||||
public final int value;
|
public final int value;
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ import org.qortal.arbitrary.misc.Service;
|
|||||||
import org.qortal.controller.Controller;
|
import org.qortal.controller.Controller;
|
||||||
import org.qortal.data.transaction.ArbitraryTransactionData;
|
import org.qortal.data.transaction.ArbitraryTransactionData;
|
||||||
import org.qortal.data.transaction.TransactionData;
|
import org.qortal.data.transaction.TransactionData;
|
||||||
import org.qortal.list.ResourceListManager;
|
|
||||||
import org.qortal.network.Network;
|
import org.qortal.network.Network;
|
||||||
import org.qortal.network.Peer;
|
import org.qortal.network.Peer;
|
||||||
import org.qortal.repository.DataException;
|
import org.qortal.repository.DataException;
|
||||||
|
@ -436,4 +436,71 @@ public class ArbitraryServiceTests extends Common {
|
|||||||
assertEquals(ValidationResult.INVALID_FILE_COUNT, service.validate(path));
|
assertEquals(ValidationResult.INVALID_FILE_COUNT, service.validate(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidPrivateData() throws IOException {
|
||||||
|
String dataString = "qortalEncryptedDatabMx4fELNTV+ifJxmv4+GcuOIJOTo+3qAvbWKNY2L1rfla5UBoEcoxbtjgZ9G7FLPb8V/Qfr0bfKWfvMmN06U/pgUdLuv2mGL2V0D3qYd1011MUzGdNG1qERjaCDz8GAi63+KnHHjfMtPgYt6bcqjs4CNV+ZZ4dIt3xxHYyVEBNc=";
|
||||||
|
|
||||||
|
// Write the data a single file in a temp path
|
||||||
|
Path path = Files.createTempDirectory("testValidPrivateData");
|
||||||
|
Path filePath = Paths.get(path.toString(), "test");
|
||||||
|
filePath.toFile().deleteOnExit();
|
||||||
|
|
||||||
|
BufferedWriter writer = new BufferedWriter(new FileWriter(filePath.toFile()));
|
||||||
|
writer.write(dataString);
|
||||||
|
writer.close();
|
||||||
|
|
||||||
|
Service service = Service.FILE_PRIVATE;
|
||||||
|
assertTrue(service.isValidationRequired());
|
||||||
|
|
||||||
|
assertEquals(ValidationResult.OK, service.validate(filePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncryptedData() throws IOException {
|
||||||
|
String dataString = "qortalEncryptedDatabMx4fELNTV+ifJxmv4+GcuOIJOTo+3qAvbWKNY2L1rfla5UBoEcoxbtjgZ9G7FLPb8V/Qfr0bfKWfvMmN06U/pgUdLuv2mGL2V0D3qYd1011MUzGdNG1qERjaCDz8GAi63+KnHHjfMtPgYt6bcqjs4CNV+ZZ4dIt3xxHYyVEBNc=";
|
||||||
|
|
||||||
|
// Write the data a single file in a temp path
|
||||||
|
Path path = Files.createTempDirectory("testValidPrivateData");
|
||||||
|
Path filePath = Paths.get(path.toString(), "test");
|
||||||
|
filePath.toFile().deleteOnExit();
|
||||||
|
|
||||||
|
BufferedWriter writer = new BufferedWriter(new FileWriter(filePath.toFile()));
|
||||||
|
writer.write(dataString);
|
||||||
|
writer.close();
|
||||||
|
|
||||||
|
// Validate a private service
|
||||||
|
Service service = Service.FILE_PRIVATE;
|
||||||
|
assertTrue(service.isValidationRequired());
|
||||||
|
assertEquals(ValidationResult.OK, service.validate(filePath));
|
||||||
|
|
||||||
|
// Validate a regular service
|
||||||
|
service = Service.FILE;
|
||||||
|
assertTrue(service.isValidationRequired());
|
||||||
|
assertEquals(ValidationResult.DATA_ENCRYPTED, service.validate(filePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPlainTextData() throws IOException {
|
||||||
|
String dataString = "plaintext";
|
||||||
|
|
||||||
|
// Write the data a single file in a temp path
|
||||||
|
Path path = Files.createTempDirectory("testInvalidPrivateData");
|
||||||
|
Path filePath = Paths.get(path.toString(), "test");
|
||||||
|
filePath.toFile().deleteOnExit();
|
||||||
|
|
||||||
|
BufferedWriter writer = new BufferedWriter(new FileWriter(filePath.toFile()));
|
||||||
|
writer.write(dataString);
|
||||||
|
writer.close();
|
||||||
|
|
||||||
|
// Validate a private service
|
||||||
|
Service service = Service.FILE_PRIVATE;
|
||||||
|
assertTrue(service.isValidationRequired());
|
||||||
|
assertEquals(ValidationResult.DATA_NOT_ENCRYPTED, service.validate(filePath));
|
||||||
|
|
||||||
|
// Validate a regular service
|
||||||
|
service = Service.FILE;
|
||||||
|
assertTrue(service.isValidationRequired());
|
||||||
|
assertEquals(ValidationResult.OK, service.validate(filePath));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user