Sanitize inputs used for the working path when building arbitrary data, and throw/handle an exception if it still doesn't work.

Should fix issue on Windows systems due to reserved characters in certain resource names.
This commit is contained in:
CalDescent 2023-07-08 14:27:24 +01:00
parent d8237abde5
commit 9694094bbf
8 changed files with 40 additions and 14 deletions

View File

@ -40,8 +40,8 @@ public class GatewayResource {
// If "build=true" has been specified in the query string, build the resource before returning its status
if (build != null && build == true) {
ArbitraryDataReader reader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, null);
try {
ArbitraryDataReader reader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, null);
if (!reader.isBuilding()) {
reader.loadSynchronously(false);
}

View File

@ -1287,8 +1287,8 @@ public class ArbitraryResource {
private HttpServletResponse download(Service service, String name, String identifier, String filepath, String encoding, boolean rebuild, boolean async, Integer maxAttempts) {
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, identifier);
try {
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, identifier);
int attempts = 0;
if (maxAttempts == null) {
@ -1394,8 +1394,8 @@ public class ArbitraryResource {
}
private FileProperties getFileProperties(Service service, String name, String identifier) {
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, identifier);
try {
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, identifier);
arbitraryDataReader.loadSynchronously(false);
java.nio.file.Path outputPath = arbitraryDataReader.getFilePath();
if (outputPath == null) {

View File

@ -66,7 +66,7 @@ public class ArbitraryDataReader {
// TODO: all builds could be handled by the build queue (even synchronous ones), to avoid the need for this
private static Map<String, Long> inProgress = Collections.synchronizedMap(new HashMap<>());
public ArbitraryDataReader(String resourceId, ResourceIdType resourceIdType, Service service, String identifier) {
public ArbitraryDataReader(String resourceId, ResourceIdType resourceIdType, Service service, String identifier) throws DataException {
// Ensure names are always lowercase
if (resourceIdType == ResourceIdType.NAME) {
resourceId = resourceId.toLowerCase();
@ -90,11 +90,16 @@ public class ArbitraryDataReader {
this.canRequestMissingFiles = true;
}
private Path buildWorkingPath() {
private Path buildWorkingPath() throws DataException {
// Use the user-specified temp dir, as it is deterministic, and is more likely to be located on reusable storage hardware
String baseDir = Settings.getInstance().getTempDataPath();
String identifier = this.identifier != null ? this.identifier : "default";
return Paths.get(baseDir, "reader", this.resourceIdType.toString(), this.resourceId, this.service.toString(), identifier);
try {
return Paths.get(baseDir, "reader", this.resourceIdType.toString(), StringUtils.sanitizeString(this.resourceId), this.service.toString(), StringUtils.sanitizeString(identifier));
} catch (InvalidPathException e) {
throw new DataException(String.format("Invalid path: %s", e.getMessage()));
}
}
public boolean isCachedDataAvailable() {

View File

@ -76,9 +76,11 @@ public class ArbitraryDataRenderer {
return ArbitraryDataRenderer.getResponse(response, 500, "QDN is disabled in settings");
}
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(resourceId, resourceIdType, service, identifier);
arbitraryDataReader.setSecret58(secret58); // Optional, used for loading encrypted file hashes only
ArbitraryDataReader arbitraryDataReader;
try {
arbitraryDataReader = new ArbitraryDataReader(resourceId, resourceIdType, service, identifier);
arbitraryDataReader.setSecret58(secret58); // Optional, used for loading encrypted file hashes only
if (!arbitraryDataReader.isCachedDataAvailable()) {
// If async is requested, show a loading screen whilst build is in progress
if (async) {

View File

@ -111,10 +111,15 @@ public class ArbitraryDataResource {
}
// Firstly check the cache to see if it's already built
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(
resourceId, resourceIdType, service, identifier);
if (arbitraryDataReader.isCachedDataAvailable()) {
return new ArbitraryResourceStatus(Status.READY, this.localChunkCount, this.totalChunkCount);
try {
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(
resourceId, resourceIdType, service, identifier);
if (arbitraryDataReader.isCachedDataAvailable()) {
return new ArbitraryResourceStatus(Status.READY, this.localChunkCount, this.totalChunkCount);
}
} catch (DataException e) {
// Assume no usable data
return new ArbitraryResourceStatus(Status.PUBLISHED, this.localChunkCount, this.totalChunkCount);
}
// Check if we have all data locally for this resource

View File

@ -117,8 +117,9 @@ public class ArbitraryDataTransactionBuilder {
}
private Method determineMethodAutomatically() throws DataException {
ArbitraryDataReader reader = new ArbitraryDataReader(this.name, ResourceIdType.NAME, this.service, this.identifier);
ArbitraryDataReader reader;
try {
reader = new ArbitraryDataReader(this.name, ResourceIdType.NAME, this.service, this.identifier);
reader.loadSynchronously(true);
} catch (Exception e) {
// Catch all exceptions if the existing resource cannot be loaded first time

View File

@ -397,8 +397,8 @@ public class ArbitraryTransactionUtils {
// If "build" has been specified, build the resource before returning its status
if (build != null && build == true) {
ArbitraryDataReader reader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, identifier);
try {
ArbitraryDataReader reader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, identifier);
if (!reader.isBuilding()) {
reader.loadSynchronously(false);
}

View File

@ -0,0 +1,13 @@
package org.qortal.utils;
public class StringUtils {
public static String sanitizeString(String input) {
String sanitized = input
.replaceAll("[<>:\"/\\\\|?*]", "") // Remove invalid characters
.replaceAll("^\\s+|\\s+$", "") // Trim leading and trailing whitespace
.replaceAll("\\s+", "_"); // Replace consecutive whitespace with underscores
return sanitized;
}
}