allow downloads

This commit is contained in:
PhilReact 2025-05-19 16:55:12 +03:00
parent 58ab02c4f0
commit ca88cb1f88

View File

@ -709,14 +709,14 @@ public class ArbitraryResource {
@QueryParam("encoding") String encoding, @QueryParam("encoding") String encoding,
@QueryParam("rebuild") boolean rebuild, @QueryParam("rebuild") boolean rebuild,
@QueryParam("async") boolean async, @QueryParam("async") boolean async,
@QueryParam("attempts") Integer attempts) { @QueryParam("attempts") Integer attempts, @QueryParam("attachment") boolean attachment, @QueryParam("attachmentFilename") String attachmentFilename) {
// Authentication can be bypassed in the settings, for those running public QDN nodes // Authentication can be bypassed in the settings, for those running public QDN nodes
if (!Settings.getInstance().isQDNAuthBypassEnabled()) { if (!Settings.getInstance().isQDNAuthBypassEnabled()) {
Security.checkApiCallAllowed(request); Security.checkApiCallAllowed(request);
} }
this.download(service, name, null, filepath, encoding, rebuild, async, attempts); this.download(service, name, null, filepath, encoding, rebuild, async, attempts, attachment, attachmentFilename);
} }
@GET @GET
@ -743,14 +743,14 @@ public class ArbitraryResource {
@QueryParam("encoding") String encoding, @QueryParam("encoding") String encoding,
@QueryParam("rebuild") boolean rebuild, @QueryParam("rebuild") boolean rebuild,
@QueryParam("async") boolean async, @QueryParam("async") boolean async,
@QueryParam("attempts") Integer attempts) { @QueryParam("attempts") Integer attempts, @QueryParam("attachment") boolean attachment, @QueryParam("attachmentFilename") String attachmentFilename) {
// Authentication can be bypassed in the settings, for those running public QDN nodes // Authentication can be bypassed in the settings, for those running public QDN nodes
if (!Settings.getInstance().isQDNAuthBypassEnabled()) { if (!Settings.getInstance().isQDNAuthBypassEnabled()) {
Security.checkApiCallAllowed(request, null); Security.checkApiCallAllowed(request, null);
} }
this.download(service, name, identifier, filepath, encoding, rebuild, async, attempts); this.download(service, name, identifier, filepath, encoding, rebuild, async, attempts, attachment, attachmentFilename);
} }
@ -1900,8 +1900,9 @@ public String finalizeUpload(
} }
} }
private void download(Service service, String name, String identifier, String filepath, String encoding, boolean rebuild, boolean async, Integer maxAttempts) { private void download(Service service, String name, String identifier, String filepath, String encoding, boolean rebuild, boolean async, Integer maxAttempts, boolean attachment, String attachmentFilename) {
try { try {
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, identifier); ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, identifier);
int attempts = 0; int attempts = 0;
@ -1948,6 +1949,33 @@ public String finalizeUpload(
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "No file exists at filepath: " + filepath); throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "No file exists at filepath: " + filepath);
} }
if (attachment) {
String rawFilename;
if (attachmentFilename != null && !attachmentFilename.isEmpty()) {
// 1. Sanitize first
String safeAttachmentFilename = attachmentFilename.replaceAll("[\\\\/:*?\"<>|]", "_");
// 2. Check for a valid extension (35 alphanumeric chars)
if (!safeAttachmentFilename.matches(".*\\.[a-zA-Z0-9]{2,5}$")) {
safeAttachmentFilename += ".bin";
}
rawFilename = safeAttachmentFilename;
} else {
// Fallback if no filename is provided
String baseFilename = (identifier != null && !identifier.isEmpty())
? name + "-" + identifier
: name;
rawFilename = baseFilename.replaceAll("[\\\\/:*?\"<>|]", "_") + ".bin";
}
// Optional: trim length
rawFilename = rawFilename.length() > 100 ? rawFilename.substring(0, 100) : rawFilename;
// 3. Set Content-Disposition header
response.setHeader("Content-Disposition", "attachment; filename=\"" + rawFilename + "\"");
}
long fileSize = Files.size(path); long fileSize = Files.size(path);
String mimeType = context.getMimeType(path.toString()); String mimeType = context.getMimeType(path.toString());
String range = request.getHeader("Range"); String range = request.getHeader("Range");