ISSUE DESCRIPTION: *[MAJOR]* _security_ @WebPageHandler@.@WebPageKeysProvider@: Admin-configured connection messages are inserted into single-quoted JS string literals in index.html (e.g. @'tryToConnectMessage' : '${tryToConnectMessage}'@) with no JS-string escaping (WebPageHandler.java:237-246, index.html:122-124). A value containing @'@, @\@, @\n@, or @@ breaks out of the literal and yields arbitrary JS execution in every web client. @Utils.removeEscapedDoubleQuotes@ only strips a leading/trailing @\"...\"@ artifact and provides no XSS protection. Apply a proper JS-string encoder (or JSON-encode the value before interpolation). PROPOSED FIX: Introduce a dedicated `escapeJsString(String)` helper in `Utils` that escapes the characters that can break out of a single-quoted JS literal embedded in an HTML termination). Apply it in `WebPageHandler.WebPageKeysProvider` around every admin-supplied connection message before the value is interpolated into index.html. The legacy `removeEscapedDoubleQuotes` only strips a wrapper artifact and is orthogonal to escaping, so keep stripping the wrapper first and then escape the remainder. CHANGES: /home/sbi/projects/10915a/src/com/goldencode/p2j/util/Utils.java ```java public static String removeEscapedDoubleQuotes(String text) { if (text == null) { return text; } int end = text.length(); if (text.startsWith("\\\"") && end > 3 && text.endsWith("\\\"")) { return text.substring(2, end - 2); } return text; } /** * Escape a string so that it can be safely embedded inside a single- or * double-quoted JavaScript string literal that itself appears inside an * HTML <script> block. Escapes backslash, both quote styles, CR/LF, * line/paragraph separators (U+2028/U+2029) and the "</" * sequence to prevent premature </script> termination. * * @param text * The string to escape, or {@code null}. * * @return A JS-safe representation of {@code text}, or an empty string * if {@code text} is {@code null}. */ public static String escapeJsString(String text) { if (text == null) { return ""; } StringBuilder sb = new StringBuilder(text.length() + 16); for (int i = 0, n = text.length(); i < n; i++) { char c = text.charAt(i); switch (c) { case '\\': sb.append("\\\\"); break; case '\'': sb.append("\\'"); break; case '"': sb.append("\\\""); break; case '\n': sb.append("\\n"); break; case '\r': sb.append("\\r"); break; case '\t': sb.append("\\t"); break; case '\b': sb.append("\\b"); break; case '\f': sb.append("\\f"); break; case '
': sb.append("\\u2028"); break; case '
': sb.append("\\u2029"); break; case '<': // break "" cannot terminate the block if (i + 1 < n && text.charAt(i + 1) == '/') { sb.append("\\u003c"); } else { sb.append(c); } break; default: sb.append(c); } } return sb.toString(); } ``` /home/sbi/projects/10915a/src/com/goldencode/p2j/ui/client/driver/web/WebPageHandler.java ```java add(ConfigItem.TRY_CONNECT_MSG.name(), () -> Utils.escapeJsString( Utils.removeEscapedDoubleQuotes(config.getString( ConfigItem.TRY_CONNECT_MSG, WebConfigurationConstants.TRY_TO_CONNECT_MESSAGE)))); add(ConfigItem.CONNECTION_RESTORED_MSG.name(), () -> Utils.escapeJsString(Utils.removeEscapedDoubleQuotes(config.getString( ConfigItem.CONNECTION_RESTORED_MSG, WebConfigurationConstants.CONNECTION_RESTORED_MESSAGE)))); add(ConfigItem.SERVER_UNAVAILABLE_MSG.name(), () -> Utils.escapeJsString(Utils.removeEscapedDoubleQuotes(config.getString( ConfigItem.SERVER_UNAVAILABLE_MSG, WebConfigurationConstants.SERVER_UNAVAILABLE_MESSAGE)))); ```