Modified storage code to support 2 new settings:

publicDataEnabled - whether to store decryptable data (default true)
privateDataEnabled - whether to store data without a decryption key (default false)
This commit is contained in:
CalDescent 2021-11-24 09:38:18 +00:00
parent f6b9ff50c3
commit 1b170c74c0
6 changed files with 59 additions and 15 deletions

View File

@ -372,6 +372,7 @@ public class ArbitraryDataReader {
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | NoSuchPaddingException
| BadPaddingException | IllegalBlockSizeException | IOException | InvalidKeyException e) {
// TODO: delete files and blacklist this resource if privateDataEnabled is false
throw new DataException(String.format("Unable to decrypt file at path %s: %s", this.filePath, e.getMessage()));
}
} else {

View File

@ -128,9 +128,9 @@ public class ArbitraryDataCleanupManager extends Thread {
// Check to see if we should be hosting data for this transaction at all
if (!storageManager.canStoreDataForName(arbitraryTransactionData.getName())) {
LOGGER.info("Deleting transaction {} because we can't host data for name {}",
Base58.encode(arbitraryTransactionData.getSignature()), arbitraryTransactionData.getName());
if (!storageManager.canStoreData(arbitraryTransactionData)) {
LOGGER.info("Deleting transaction {} because we can't host its data",
Base58.encode(arbitraryTransactionData.getSignature()));
ArbitraryTransactionUtils.deleteCompleteFileAndChunks(arbitraryTransactionData);
continue;
}

View File

@ -190,7 +190,7 @@ public class ArbitraryDataManager extends Thread {
ArbitraryTransactionData arbitraryTransactionData = (ArbitraryTransactionData) arbitraryTransaction.getTransactionData();
// Skip transactions that we don't need to proactively store data for
if (!storageManager.shouldPreFetchDataForName(arbitraryTransactionData.getName())) {
if (!storageManager.shouldPreFetchData(arbitraryTransactionData)) {
iterator.remove();
continue;
}
@ -680,7 +680,7 @@ public class ArbitraryDataManager extends Thread {
// We may also need to broadcast to the network that we are now hosting files for this transaction,
// but only if these files are in accordance with our storage policy
if (ArbitraryDataStorageManager.getInstance().canStoreDataForName(arbitraryTransactionData.getName())) {
if (ArbitraryDataStorageManager.getInstance().canStoreData(arbitraryTransactionData)) {
// Use a null peer address to indicate our own
Message newArbitrarySignatureMessage = new ArbitrarySignaturesMessage(null, Arrays.asList(signature));
Network.getInstance().broadcast(broadcastPeer -> newArbitrarySignatureMessage);
@ -863,7 +863,7 @@ public class ArbitraryDataManager extends Thread {
if (transactionData instanceof ArbitraryTransactionData) {
// Check if we're even allowed to serve data for this transaction
if (ArbitraryDataStorageManager.getInstance().canStoreDataForName(transactionData.getName())) {
if (ArbitraryDataStorageManager.getInstance().canStoreData(transactionData)) {
byte[] hash = transactionData.getData();
byte[] chunkHashes = transactionData.getChunkHashes();

View File

@ -1,5 +1,6 @@
package org.qortal.controller.arbitrary;
import org.qortal.data.transaction.ArbitraryTransactionData;
import org.qortal.list.ResourceListManager;
import org.qortal.settings.Settings;
@ -25,7 +26,14 @@ public class ArbitraryDataStorageManager {
return instance;
}
public boolean canStoreDataForName(String name) {
public boolean canStoreData(ArbitraryTransactionData arbitraryTransactionData) {
String name = arbitraryTransactionData.getName();
// Don't store data unless it's an allowed type (public/private)
if (!this.isDataTypeAllowed(arbitraryTransactionData)) {
return false;
}
// Check if our storage policy and blacklist allows us to host data for this name
switch (Settings.getInstance().getStoragePolicy()) {
case FOLLOWED_AND_VIEWED:
@ -45,18 +53,19 @@ public class ArbitraryDataStorageManager {
}
}
public boolean isNameInBlacklist(String name) {
return ResourceListManager.getInstance().listContains("blacklist", "names", name, false);
}
public boolean shouldPreFetchDataForName(String name) {
public boolean shouldPreFetchData(ArbitraryTransactionData arbitraryTransactionData) {
String name = arbitraryTransactionData.getName();
if (name == null) {
return this.shouldPreFetchDataWithoutName();
return this.shouldPreFetchDataWithoutName(arbitraryTransactionData);
}
// Never fetch data from blacklisted names, even if they are followed
if (this.isNameInBlacklist(name)) {
return false;
}
// Don't store data unless it's an allowed type (public/private)
if (!this.isDataTypeAllowed(arbitraryTransactionData)) {
return false;
}
switch (Settings.getInstance().getStoragePolicy()) {
case FOLLOWED:
@ -73,10 +82,10 @@ public class ArbitraryDataStorageManager {
}
}
private boolean shouldPreFetchDataWithoutName() {
private boolean shouldPreFetchDataWithoutName(ArbitraryTransactionData arbitraryTransactionData) {
switch (Settings.getInstance().getStoragePolicy()) {
case ALL:
return true;
return this.isDataTypeAllowed(arbitraryTransactionData);
case NONE:
case VIEWED:
@ -87,6 +96,25 @@ public class ArbitraryDataStorageManager {
}
}
private boolean isDataTypeAllowed(ArbitraryTransactionData arbitraryTransactionData) {
byte[] secret = arbitraryTransactionData.getSecret();
boolean hasSecret = (secret != null && secret.length == 32);
if (!Settings.getInstance().isPrivateDataEnabled() && !hasSecret) {
// Private data isn't enabled so we can't store data without a valid secret
return false;
}
if (!Settings.getInstance().isPublicDataEnabled() && hasSecret) {
// Public data isn't enabled so we can't store data with a secret
return false;
}
return true;
}
public boolean isNameInBlacklist(String name) {
return ResourceListManager.getInstance().listContains("blacklist", "names", name, false);
}
private boolean isFollowingName(String name) {
return ResourceListManager.getInstance().listContains("followed", "names", name, false);
}

View File

@ -284,6 +284,11 @@ public class Settings {
/** Whether to validate every layer when building arbitrary data, or just the final layer */
private boolean validateAllDataLayers = false;
/** Whether to allow public (decryptable) data to be stored */
private boolean publicDataEnabled = true;
/** Whether to allow private (non-decryptable) data to be stored */
private boolean privateDataEnabled = false;
// Domain mapping
public static class DomainMap {
@ -827,4 +832,12 @@ public class Settings {
public boolean shouldValidateAllDataLayers() {
return this.validateAllDataLayers;
}
public boolean isPublicDataEnabled() {
return this.publicDataEnabled;
}
public boolean isPrivateDataEnabled() {
return this.privateDataEnabled;
}
}

View File

@ -0,0 +1,2 @@
package org.qortal.test.arbitrary;public class ArbitraryDataStoragePolicyTests {
}