pass ui lang to qapps

This commit is contained in:
PhilReact 2025-05-10 22:21:13 +03:00
parent 88d009c979
commit 70ae122f5c
5 changed files with 47 additions and 21 deletions

View File

@ -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

View File

@ -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());

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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;
}