mirror of
https://github.com/Qortal/qortal.git
synced 2025-07-19 19:01:22 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
f5a4a0a16c
@ -1,14 +1,13 @@
|
||||
package org.qortal.api;
|
||||
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.select.Elements;
|
||||
import org.qortal.arbitrary.misc.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class HTMLParser {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(HTMLParser.class);
|
||||
@ -22,10 +21,11 @@ public class HTMLParser {
|
||||
private String identifier;
|
||||
private String path;
|
||||
private String theme;
|
||||
private String lang;
|
||||
private boolean usingCustomRouting;
|
||||
|
||||
public HTMLParser(String resourceId, String inPath, String prefix, boolean includeResourceIdInPrefix, byte[] data,
|
||||
String qdnContext, Service service, String identifier, String theme, boolean usingCustomRouting) {
|
||||
String qdnContext, Service service, String identifier, String theme, boolean usingCustomRouting, String lang) {
|
||||
String inPathWithoutFilename = inPath.contains("/") ? inPath.substring(0, inPath.lastIndexOf('/')) : String.format("/%s",inPath);
|
||||
this.qdnBase = includeResourceIdInPrefix ? String.format("%s/%s", prefix, resourceId) : prefix;
|
||||
this.qdnBaseWithPath = includeResourceIdInPrefix ? String.format("%s/%s%s", prefix, resourceId, inPathWithoutFilename) : String.format("%s%s", prefix, inPathWithoutFilename);
|
||||
@ -36,6 +36,7 @@ public class HTMLParser {
|
||||
this.identifier = identifier;
|
||||
this.path = inPath;
|
||||
this.theme = theme;
|
||||
this.lang = lang;
|
||||
this.usingCustomRouting = usingCustomRouting;
|
||||
}
|
||||
|
||||
@ -61,9 +62,13 @@ public class HTMLParser {
|
||||
String identifier = this.identifier != null ? this.identifier.replace("\\", "").replace("\"","\\\"") : "";
|
||||
String path = this.path != null ? this.path.replace("\\", "").replace("\"","\\\"") : "";
|
||||
String theme = this.theme != null ? this.theme.replace("\\", "").replace("\"","\\\"") : "";
|
||||
String lang = this.lang != null ? this.lang.replace("\\", "").replace("\"", "\\\"") : "";
|
||||
String qdnBase = this.qdnBase != null ? this.qdnBase.replace("\\", "").replace("\"","\\\"") : "";
|
||||
String qdnBaseWithPath = this.qdnBaseWithPath != null ? this.qdnBaseWithPath.replace("\\", "").replace("\"","\\\"") : "";
|
||||
String qdnContextVar = String.format("<script>var _qdnContext=\"%s\"; var _qdnTheme=\"%s\"; var _qdnService=\"%s\"; var _qdnName=\"%s\"; var _qdnIdentifier=\"%s\"; var _qdnPath=\"%s\"; var _qdnBase=\"%s\"; var _qdnBaseWithPath=\"%s\";</script>", qdnContext, theme, service, name, identifier, path, qdnBase, qdnBaseWithPath);
|
||||
String qdnContextVar = String.format(
|
||||
"<script>var _qdnContext=\"%s\"; var _qdnTheme=\"%s\"; var _qdnLang=\"%s\"; var _qdnService=\"%s\"; var _qdnName=\"%s\"; var _qdnIdentifier=\"%s\"; var _qdnPath=\"%s\"; var _qdnBase=\"%s\"; var _qdnBaseWithPath=\"%s\";</script>",
|
||||
qdnContext, theme, lang, service, name, identifier, path, qdnBase, qdnBaseWithPath
|
||||
);
|
||||
head.get(0).prepend(qdnContextVar);
|
||||
|
||||
// Add base href tag
|
||||
|
@ -142,10 +142,20 @@ public class DevProxyServerResource {
|
||||
}
|
||||
}
|
||||
|
||||
String lang = request.getParameter("lang");
|
||||
if (lang == null || lang.isBlank()) {
|
||||
lang = "en"; // fallback
|
||||
}
|
||||
|
||||
String theme = request.getParameter("theme");
|
||||
if (theme == null || theme.isBlank()) {
|
||||
theme = "light";
|
||||
}
|
||||
|
||||
// Parse and modify output if needed
|
||||
if (HTMLParser.isHtmlFile(filename)) {
|
||||
// HTML file - needs to be parsed
|
||||
HTMLParser htmlParser = new HTMLParser("", inPath, "", false, data, "proxy", Service.APP, null, "light", true);
|
||||
HTMLParser htmlParser = new HTMLParser("", inPath, "", false, data, "proxy", Service.APP, null, theme , true, lang);
|
||||
htmlParser.addAdditionalHeaderTags();
|
||||
response.addHeader("Content-Security-Policy", "default-src 'self' 'unsafe-inline' 'unsafe-eval'; media-src 'self' data: blob:; img-src 'self' data: blob:; connect-src 'self' ws:; font-src 'self' data:;");
|
||||
response.setContentType(con.getContentType());
|
||||
|
@ -71,33 +71,33 @@ public class RenderResource {
|
||||
@Path("/signature/{signature}")
|
||||
@SecurityRequirement(name = "apiKey")
|
||||
public HttpServletResponse getIndexBySignature(@PathParam("signature") String signature,
|
||||
@QueryParam("theme") String theme) {
|
||||
@QueryParam("theme") String theme, @QueryParam("lang") String lang) {
|
||||
if (!Settings.getInstance().isQDNAuthBypassEnabled())
|
||||
Security.requirePriorAuthorization(request, signature, Service.WEBSITE, null);
|
||||
|
||||
return this.get(signature, ResourceIdType.SIGNATURE, null, null, "/", null, "/render/signature", true, true, theme);
|
||||
return this.get(signature, ResourceIdType.SIGNATURE, null, null, "/", null, "/render/signature", true, true, theme, lang);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/signature/{signature}/{path:.*}")
|
||||
@SecurityRequirement(name = "apiKey")
|
||||
public HttpServletResponse getPathBySignature(@PathParam("signature") String signature, @PathParam("path") String inPath,
|
||||
@QueryParam("theme") String theme) {
|
||||
@QueryParam("theme") String theme, @QueryParam("lang") String lang) {
|
||||
if (!Settings.getInstance().isQDNAuthBypassEnabled())
|
||||
Security.requirePriorAuthorization(request, signature, Service.WEBSITE, null);
|
||||
|
||||
return this.get(signature, ResourceIdType.SIGNATURE, null, null, inPath,null, "/render/signature", true, true, theme);
|
||||
return this.get(signature, ResourceIdType.SIGNATURE, null, null, inPath,null, "/render/signature", true, true, theme, lang);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/hash/{hash}")
|
||||
@SecurityRequirement(name = "apiKey")
|
||||
public HttpServletResponse getIndexByHash(@PathParam("hash") String hash58, @QueryParam("secret") String secret58,
|
||||
@QueryParam("theme") String theme) {
|
||||
@QueryParam("theme") String theme, @QueryParam("lang") String lang) {
|
||||
if (!Settings.getInstance().isQDNAuthBypassEnabled())
|
||||
Security.requirePriorAuthorization(request, hash58, Service.WEBSITE, null);
|
||||
|
||||
return this.get(hash58, ResourceIdType.FILE_HASH, Service.ARBITRARY_DATA, null, "/", secret58, "/render/hash", true, false, theme);
|
||||
return this.get(hash58, ResourceIdType.FILE_HASH, Service.ARBITRARY_DATA, null, "/", secret58, "/render/hash", true, false, theme, lang);
|
||||
}
|
||||
|
||||
@GET
|
||||
@ -105,11 +105,11 @@ public class RenderResource {
|
||||
@SecurityRequirement(name = "apiKey")
|
||||
public HttpServletResponse getPathByHash(@PathParam("hash") String hash58, @PathParam("path") String inPath,
|
||||
@QueryParam("secret") String secret58,
|
||||
@QueryParam("theme") String theme) {
|
||||
@QueryParam("theme") String theme, @QueryParam("lang") String lang) {
|
||||
if (!Settings.getInstance().isQDNAuthBypassEnabled())
|
||||
Security.requirePriorAuthorization(request, hash58, Service.WEBSITE, null);
|
||||
|
||||
return this.get(hash58, ResourceIdType.FILE_HASH, Service.ARBITRARY_DATA, null, inPath, secret58, "/render/hash", true, false, theme);
|
||||
return this.get(hash58, ResourceIdType.FILE_HASH, Service.ARBITRARY_DATA, null, inPath, secret58, "/render/hash", true, false, theme, lang);
|
||||
}
|
||||
|
||||
@GET
|
||||
@ -119,12 +119,12 @@ public class RenderResource {
|
||||
@PathParam("name") String name,
|
||||
@PathParam("path") String inPath,
|
||||
@QueryParam("identifier") String identifier,
|
||||
@QueryParam("theme") String theme) {
|
||||
@QueryParam("theme") String theme, @QueryParam("lang") String lang) {
|
||||
if (!Settings.getInstance().isQDNAuthBypassEnabled())
|
||||
Security.requirePriorAuthorization(request, name, service, null);
|
||||
|
||||
String prefix = String.format("/render/%s", service);
|
||||
return this.get(name, ResourceIdType.NAME, service, identifier, inPath, null, prefix, true, true, theme);
|
||||
return this.get(name, ResourceIdType.NAME, service, identifier, inPath, null, prefix, true, true, theme, lang);
|
||||
}
|
||||
|
||||
@GET
|
||||
@ -133,18 +133,18 @@ public class RenderResource {
|
||||
public HttpServletResponse getIndexByName(@PathParam("service") Service service,
|
||||
@PathParam("name") String name,
|
||||
@QueryParam("identifier") String identifier,
|
||||
@QueryParam("theme") String theme) {
|
||||
@QueryParam("theme") String theme, @QueryParam("lang") String lang) {
|
||||
if (!Settings.getInstance().isQDNAuthBypassEnabled())
|
||||
Security.requirePriorAuthorization(request, name, service, null);
|
||||
|
||||
String prefix = String.format("/render/%s", service);
|
||||
return this.get(name, ResourceIdType.NAME, service, identifier, "/", null, prefix, true, true, theme);
|
||||
return this.get(name, ResourceIdType.NAME, service, identifier, "/", null, prefix, true, true, theme, lang);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private HttpServletResponse get(String resourceId, ResourceIdType resourceIdType, Service service, String identifier,
|
||||
String inPath, String secret58, String prefix, boolean includeResourceIdInPrefix, boolean async, String theme) {
|
||||
String inPath, String secret58, String prefix, boolean includeResourceIdInPrefix, boolean async, String theme, String lang) {
|
||||
|
||||
ArbitraryDataRenderer renderer = new ArbitraryDataRenderer(resourceId, resourceIdType, service, identifier, inPath,
|
||||
secret58, prefix, includeResourceIdInPrefix, async, "render", request, response, context);
|
||||
@ -152,6 +152,9 @@ public class RenderResource {
|
||||
if (theme != null) {
|
||||
renderer.setTheme(theme);
|
||||
}
|
||||
if (lang != null) {
|
||||
renderer.setLang(lang);
|
||||
}
|
||||
return renderer.render();
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,7 @@ public class ArbitraryDataRenderer {
|
||||
private final Service service;
|
||||
private final String identifier;
|
||||
private String theme = "light";
|
||||
private String lang = "en";
|
||||
private String inPath;
|
||||
private final String secret58;
|
||||
private final String prefix;
|
||||
@ -166,7 +167,7 @@ public class ArbitraryDataRenderer {
|
||||
if (HTMLParser.isHtmlFile(filename)) {
|
||||
// HTML file - needs to be parsed
|
||||
byte[] data = Files.readAllBytes(filePath); // TODO: limit file size that can be read into memory
|
||||
HTMLParser htmlParser = new HTMLParser(resourceId, inPath, prefix, includeResourceIdInPrefix, data, qdnContext, service, identifier, theme, usingCustomRouting);
|
||||
HTMLParser htmlParser = new HTMLParser(resourceId, inPath, prefix, includeResourceIdInPrefix, data, qdnContext, service, identifier, theme, usingCustomRouting, lang);
|
||||
htmlParser.addAdditionalHeaderTags();
|
||||
response.addHeader("Content-Security-Policy", "default-src 'self' 'unsafe-inline' 'unsafe-eval'; font-src 'self' data:; media-src 'self' data: blob:; img-src 'self' data: blob:; connect-src 'self' wss:;");
|
||||
response.setContentType(context.getMimeType(filename));
|
||||
@ -256,5 +257,8 @@ public class ArbitraryDataRenderer {
|
||||
public void setTheme(String theme) {
|
||||
this.theme = theme;
|
||||
}
|
||||
public void setLang(String lang) {
|
||||
this.lang = lang;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ function parseUrl(url) {
|
||||
|
||||
// Remove theme, identifier, and time queries if they exist
|
||||
parsedUrl.searchParams.delete("theme");
|
||||
parsedUrl.searchParams.delete("lang");
|
||||
parsedUrl.searchParams.delete("identifier");
|
||||
parsedUrl.searchParams.delete("time");
|
||||
parsedUrl.searchParams.delete("isManualNavigation");
|
||||
@ -213,8 +214,11 @@ function buildResourceUrl(service, name, identifier, path, isLink) {
|
||||
if (path != null) url = url.concat((path.startsWith("/") ? "" : "/") + path);
|
||||
}
|
||||
|
||||
if (isLink) url = url.concat((url.includes("?") ? "" : "?") + "&theme=" + _qdnTheme);
|
||||
|
||||
if (isLink) {
|
||||
const hasQuery = url.includes("?");
|
||||
const queryPrefix = hasQuery ? "&" : "?";
|
||||
url += queryPrefix + "theme=" + _qdnTheme + "&lang=" + _qdnLang;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user