From 5ace6df6bbbd84aecfad37c08ada91a33084643b Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Thu, 2 Jul 2026 18:11:24 +0100 Subject: [PATCH 1/4] `FormattedTextHelper`: stricter URL parsing --- .../utilities/FormattedTextHelper.java | 43 ++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java index 67392b5fa9..ddc0e08258 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java @@ -3,10 +3,7 @@ import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.objects.properties.bukkit.BukkitElementExtensions; -import com.denizenscript.denizencore.objects.core.ColorTag; -import com.denizenscript.denizencore.objects.core.ElementTag; -import com.denizenscript.denizencore.objects.core.ListTag; -import com.denizenscript.denizencore.objects.core.MapTag; +import com.denizenscript.denizencore.objects.core.*; import com.denizenscript.denizencore.utilities.AsciiMatcher; import com.denizenscript.denizencore.utilities.CoreConfiguration; import com.denizenscript.denizencore.utilities.CoreUtilities; @@ -19,6 +16,8 @@ import net.md_5.bungee.chat.ComponentSerializer; import net.md_5.bungee.chat.VersionedComponentSerializer; +import java.net.URI; +import java.net.URISyntaxException; import java.util.List; public class FormattedTextHelper { @@ -800,11 +799,17 @@ else if (code == 'o' || code == 'O') { else if (i + "https://a.".length() < chars.length && chars[i] == 'h' && chars[i + 1] == 't' && chars[i + 2] == 't' && chars[i + 3] == 'p') { String subStr = str.substring(i, i + "https://a.".length()); if (subStr.startsWith("https://") || subStr.startsWith("http://")) { - int nextSpace = CoreUtilities.indexOfAny(str, i, ' ', '\t', '\n', ChatColor.COLOR_CHAR); - if (nextSpace == -1) { - nextSpace = str.length(); + int urlEnd = findUrlEndIndex(chars, i); + if (urlEnd - i < "https://a.".length()) { + continue; + } + String url = str.substring(i, urlEnd); + try { + new URI(url); + } + catch (URISyntaxException ignored) { + continue; } - String url = str.substring(i, nextSpace); nextText.setText(nextText.getText() + str.substring(started, i)); base.addExtra(nextText); lastText = nextText; @@ -813,8 +818,8 @@ else if (i + "https://a.".length() < chars.length && chars[i] == 'h' && chars[i TextComponent clickableText = new TextComponent(url); clickableText.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)); lastText.addExtra(clickableText); - i = nextSpace - 1; - started = nextSpace; + i = urlEnd - 1; + started = urlEnd; continue; } } @@ -826,6 +831,24 @@ else if (i + "https://a.".length() < chars.length && chars[i] == 'h' && chars[i return new BaseComponent[] { cleanBase && !optimize ? root : base }; } + public static final AsciiMatcher URL_VALID = new AsciiMatcher(AsciiMatcher.LETTERS_LOWER + AsciiMatcher.LETTERS_UPPER + AsciiMatcher.DIGITS + "-._~:/?#@!$&'()*+,;="); + + public static int findUrlEndIndex(char[] chars, int start) { + for (int i = start; i < chars.length; i++) { + char current = chars[i]; + if (current == '%') { + if (i + 2 >= chars.length || !BinaryTag.VALID_HEX.isMatch(chars[i + 1]) || !BinaryTag.VALID_HEX.isMatch(chars[i + 2])) { + return i; + } + i += 2; + } + else if (!URL_VALID.isMatch(current)) { + return i; + } + } + return chars.length; + } + public static int indexOfLastColorBlockStart(String text) { int result = text.lastIndexOf(ChatColor.COLOR_CHAR + "["); if (result == -1 || text.indexOf(']', result + 2) != -1) { From 4c1c820c51827bcd6eb74da8c1e6c2534e0d5df3 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 5 Jul 2026 13:31:38 +0100 Subject: [PATCH 2/4] simplify logic --- .../denizen/utilities/FormattedTextHelper.java | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java index ddc0e08258..4f6ab2ff93 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java @@ -799,7 +799,7 @@ else if (code == 'o' || code == 'O') { else if (i + "https://a.".length() < chars.length && chars[i] == 'h' && chars[i + 1] == 't' && chars[i + 2] == 't' && chars[i + 3] == 'p') { String subStr = str.substring(i, i + "https://a.".length()); if (subStr.startsWith("https://") || subStr.startsWith("http://")) { - int urlEnd = findUrlEndIndex(chars, i); + int urlEnd = indexOfUrlEnd(chars, i); if (urlEnd - i < "https://a.".length()) { continue; } @@ -831,18 +831,11 @@ else if (i + "https://a.".length() < chars.length && chars[i] == 'h' && chars[i return new BaseComponent[] { cleanBase && !optimize ? root : base }; } - public static final AsciiMatcher URL_VALID = new AsciiMatcher(AsciiMatcher.LETTERS_LOWER + AsciiMatcher.LETTERS_UPPER + AsciiMatcher.DIGITS + "-._~:/?#@!$&'()*+,;="); + public static final AsciiMatcher URL_VALID = new AsciiMatcher(AsciiMatcher.LETTERS_LOWER + AsciiMatcher.LETTERS_UPPER + AsciiMatcher.DIGITS + "-._~:/?#@!$&'()*+,;=%"); - public static int findUrlEndIndex(char[] chars, int start) { + public static int indexOfUrlEnd(char[] chars, int start) { for (int i = start; i < chars.length; i++) { - char current = chars[i]; - if (current == '%') { - if (i + 2 >= chars.length || !BinaryTag.VALID_HEX.isMatch(chars[i + 1]) || !BinaryTag.VALID_HEX.isMatch(chars[i + 2])) { - return i; - } - i += 2; - } - else if (!URL_VALID.isMatch(current)) { + if (!URL_VALID.isMatch(chars[i])) { return i; } } From a347433b0feedd7248c1ac06aaf3f2af1195694b Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Sun, 5 Jul 2026 13:32:12 +0100 Subject: [PATCH 3/4] imports --- .../denizenscript/denizen/utilities/FormattedTextHelper.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java index 4f6ab2ff93..82ac1a74fc 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java @@ -3,7 +3,10 @@ import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.objects.properties.bukkit.BukkitElementExtensions; -import com.denizenscript.denizencore.objects.core.*; +import com.denizenscript.denizencore.objects.core.ColorTag; +import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizencore.objects.core.ListTag; +import com.denizenscript.denizencore.objects.core.MapTag; import com.denizenscript.denizencore.utilities.AsciiMatcher; import com.denizenscript.denizencore.utilities.CoreConfiguration; import com.denizenscript.denizencore.utilities.CoreUtilities; From 72062e562c1c6034a62714984e1b80b2e09d8cc0 Mon Sep 17 00:00:00 2001 From: Aya <31237389+tal5@users.noreply.github.com> Date: Mon, 6 Jul 2026 00:24:55 +0100 Subject: [PATCH 4/4] minor optimization --- .../denizenscript/denizen/utilities/FormattedTextHelper.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java index 82ac1a74fc..f253ece61c 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/FormattedTextHelper.java @@ -800,8 +800,7 @@ else if (code == 'o' || code == 'O') { started = i + 1; } else if (i + "https://a.".length() < chars.length && chars[i] == 'h' && chars[i + 1] == 't' && chars[i + 2] == 't' && chars[i + 3] == 'p') { - String subStr = str.substring(i, i + "https://a.".length()); - if (subStr.startsWith("https://") || subStr.startsWith("http://")) { + if (str.startsWith("https://", i) || str.startsWith("http://", i)) { int urlEnd = indexOfUrlEnd(chars, i); if (urlEnd - i < "https://a.".length()) { continue;