mirror of
https://github.com/AtlasMediaGroup/Scissors.git
synced 2024-11-14 19:34:54 -05:00
Add depth limit to Component deserializer (1.19.4) (#84)
* Add depth limit to Component deserializer * Make depth limit configurable; increase placeholder penalty
This commit is contained in:
parent
ae17467c1b
commit
cbfc1beb6a
11 changed files with 166 additions and 105 deletions
|
@ -1,102 +0,0 @@
|
||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: VideoGameSmash12 <videogamesm12@gmail.com>
|
|
||||||
Date: Thu, 16 Mar 2023 01:42:08 -0500
|
|
||||||
Subject: [PATCH] Reject translatable components with more than 32 placeholders
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/network/chat/Component.java b/src/main/java/net/minecraft/network/chat/Component.java
|
|
||||||
index 3c0ee4e1f42f6056ca86a6f9f129d467e29a2fbc..534f1e6092d2b64b6e6e3182eac0cc38718ab2f8 100644
|
|
||||||
--- a/src/main/java/net/minecraft/network/chat/Component.java
|
|
||||||
+++ b/src/main/java/net/minecraft/network/chat/Component.java
|
|
||||||
@@ -26,6 +26,7 @@ import java.util.List;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Optional;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
+
|
|
||||||
import net.minecraft.ChatFormatting;
|
|
||||||
import net.minecraft.Util;
|
|
||||||
import net.minecraft.network.chat.contents.BlockDataSource;
|
|
||||||
@@ -44,6 +45,9 @@ import net.minecraft.util.GsonHelper;
|
|
||||||
import net.minecraft.util.LowerCaseEnumTypeAdapterFactory;
|
|
||||||
// CraftBukkit start
|
|
||||||
import com.google.common.collect.Streams;
|
|
||||||
+
|
|
||||||
+import java.util.regex.Matcher;
|
|
||||||
+import java.util.regex.Pattern;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
// CraftBukkit end
|
|
||||||
|
|
||||||
@@ -255,6 +259,58 @@ public interface Component extends Message, FormattedText, Iterable<Component> {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
+ private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("%[0-9]{1,}\\$s");
|
|
||||||
+
|
|
||||||
+ // Scissors start - Calculate number of placeholders in translatable components before serializing them
|
|
||||||
+ private long calculatePlaceholderCount(JsonElement element)
|
|
||||||
+ {
|
|
||||||
+ long amount = 0;
|
|
||||||
+
|
|
||||||
+ if (!element.isJsonObject())
|
|
||||||
+ {
|
|
||||||
+ return amount;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ JsonObject from = element.getAsJsonObject();
|
|
||||||
+
|
|
||||||
+ // Figure out how many placeholders are in a single translatable component
|
|
||||||
+ if (from.has("translate") && from.get("translate").isJsonPrimitive())
|
|
||||||
+ {
|
|
||||||
+ String key = GsonHelper.getAsString(from, "translate");
|
|
||||||
+ Matcher matcher = PLACEHOLDER_PATTERN.matcher(key);
|
|
||||||
+ amount += matcher.results().count();
|
|
||||||
+
|
|
||||||
+ // Recursively figure out how many placeholders the component has in the "with" shit
|
|
||||||
+ if (from.has("with") && from.get("with").isJsonArray())
|
|
||||||
+ {
|
|
||||||
+ JsonArray array = GsonHelper.getAsJsonArray(from, "with");
|
|
||||||
+
|
|
||||||
+ for (JsonElement within : array)
|
|
||||||
+ {
|
|
||||||
+ long amountWithin = calculatePlaceholderCount(within);
|
|
||||||
+
|
|
||||||
+ if (amountWithin == 1)
|
|
||||||
+ {
|
|
||||||
+ amount++;
|
|
||||||
+ }
|
|
||||||
+ else if (amountWithin > 1)
|
|
||||||
+ {
|
|
||||||
+ amount = amount * amountWithin;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ // Also applies to keybind components, but to a lesser extent
|
|
||||||
+ else if (from.has("keybind") && from.get("keybind").isJsonPrimitive())
|
|
||||||
+ {
|
|
||||||
+ String key = GsonHelper.getAsString(from, "keybind");
|
|
||||||
+ Matcher matcher = PLACEHOLDER_PATTERN.matcher(key);
|
|
||||||
+ amount += matcher.results().count();
|
|
||||||
+ }
|
|
||||||
+ return amount;
|
|
||||||
+ }
|
|
||||||
+ // Scissors end
|
|
||||||
+
|
|
||||||
public Serializer() {}
|
|
||||||
|
|
||||||
public MutableComponent deserialize(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException {
|
|
||||||
@@ -287,6 +343,14 @@ public interface Component extends Message, FormattedText, Iterable<Component> {
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
JsonObject jsonobject = jsonelement.getAsJsonObject();
|
|
||||||
+
|
|
||||||
+ // Scissors start - Reject translatable components with more than 32 placeholders in them
|
|
||||||
+ if (calculatePlaceholderCount(jsonobject) > 32)
|
|
||||||
+ {
|
|
||||||
+ return Component.empty().append("*** Component has too many placeholders ***").withStyle(ChatFormatting.RED);
|
|
||||||
+ }
|
|
||||||
+ // Scissors end
|
|
||||||
+
|
|
||||||
String s;
|
|
||||||
|
|
||||||
if (jsonobject.has("text")) {
|
|
|
@ -5,7 +5,7 @@ Subject: [PATCH] Prevent player banning using duplicate UUIDs
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
index 3bb63a652aca3c23f5f1bbf9cb70fce6540f2e33..934c0d14bd4ac1ece0c0f6add0e3e996e85a9b93 100644
|
index 45804711255f04110e9509df8d60900314aa10b7..b1fd209b2893d2d6bfc2ae552c7919ab8abda695 100644
|
||||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
@@ -1468,7 +1468,14 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
@@ -1468,7 +1468,14 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
@ -5,10 +5,10 @@ Subject: [PATCH] Fix component extra empty array exploit
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/network/chat/Component.java b/src/main/java/net/minecraft/network/chat/Component.java
|
diff --git a/src/main/java/net/minecraft/network/chat/Component.java b/src/main/java/net/minecraft/network/chat/Component.java
|
||||||
index 534f1e6092d2b64b6e6e3182eac0cc38718ab2f8..7fcab29427ea030c0d9dcb6ce237b67d98420b55 100644
|
index 3c0ee4e1f42f6056ca86a6f9f129d467e29a2fbc..9c2c22ee548ad77f0912698f33de5f467f32fb7f 100644
|
||||||
--- a/src/main/java/net/minecraft/network/chat/Component.java
|
--- a/src/main/java/net/minecraft/network/chat/Component.java
|
||||||
+++ b/src/main/java/net/minecraft/network/chat/Component.java
|
+++ b/src/main/java/net/minecraft/network/chat/Component.java
|
||||||
@@ -322,6 +322,11 @@ public interface Component extends Message, FormattedText, Iterable<Component> {
|
@@ -266,6 +266,11 @@ public interface Component extends Message, FormattedText, Iterable<Component> {
|
||||||
if (!jsonelement.isJsonObject()) {
|
if (!jsonelement.isJsonObject()) {
|
||||||
if (jsonelement.isJsonArray()) {
|
if (jsonelement.isJsonArray()) {
|
||||||
JsonArray jsonarray = jsonelement.getAsJsonArray();
|
JsonArray jsonarray = jsonelement.getAsJsonArray();
|
|
@ -0,0 +1,163 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Luna <lunahatesgogle@gmail.com>
|
||||||
|
Date: Wed, 31 May 2023 18:14:00 -0300
|
||||||
|
Subject: [PATCH] Add depth limit to Component deserializer
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/me/totalfreedom/scissors/ScissorsConfig.java b/src/main/java/me/totalfreedom/scissors/ScissorsConfig.java
|
||||||
|
index 39b56ca496ed7369ead21805d476c2b813fcdd1d..9659cff6412584190ff0c32e01f602de4ff7d3b3 100644
|
||||||
|
--- a/src/main/java/me/totalfreedom/scissors/ScissorsConfig.java
|
||||||
|
+++ b/src/main/java/me/totalfreedom/scissors/ScissorsConfig.java
|
||||||
|
@@ -87,8 +87,8 @@ public class ScissorsConfig
|
||||||
|
config.options().header(HEADER);
|
||||||
|
config.options().copyDefaults(true);
|
||||||
|
|
||||||
|
- version = getInt("config-version", 4);
|
||||||
|
- set("config-version", 4);
|
||||||
|
+ version = getInt("config-version", 5);
|
||||||
|
+ set("config-version", 5);
|
||||||
|
readConfig(ScissorsConfig.class, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -175,6 +175,12 @@ public class ScissorsConfig
|
||||||
|
excludePlayersFromNbtComponents = getBoolean("excludePlayersFromNbtComponents", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ public static int componentDepthLimit = 128;
|
||||||
|
+ private static void componentDepthLimit()
|
||||||
|
+ {
|
||||||
|
+ componentDepthLimit = getInt("componentDepthLimit", 128);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
private static void set(String path, Object val)
|
||||||
|
{
|
||||||
|
config.set(path, val);
|
||||||
|
diff --git a/src/main/java/net/minecraft/network/chat/Component.java b/src/main/java/net/minecraft/network/chat/Component.java
|
||||||
|
index 9c2c22ee548ad77f0912698f33de5f467f32fb7f..ba2879b25e59290ab81501458414a417c121ed03 100644
|
||||||
|
--- a/src/main/java/net/minecraft/network/chat/Component.java
|
||||||
|
+++ b/src/main/java/net/minecraft/network/chat/Component.java
|
||||||
|
@@ -26,6 +26,7 @@ import java.util.List;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Optional;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
+import me.totalfreedom.scissors.ScissorsConfig; // Scissors
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.Util;
|
||||||
|
import net.minecraft.network.chat.contents.BlockDataSource;
|
||||||
|
@@ -44,6 +45,7 @@ import net.minecraft.util.GsonHelper;
|
||||||
|
import net.minecraft.util.LowerCaseEnumTypeAdapterFactory;
|
||||||
|
// CraftBukkit start
|
||||||
|
import com.google.common.collect.Streams;
|
||||||
|
+import java.util.regex.Pattern; // Scissors
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
@@ -254,10 +256,16 @@ public interface Component extends Message, FormattedText, Iterable<Component> {
|
||||||
|
throw new IllegalStateException("Couldn't get field 'lineStart' for JsonReader", nosuchfieldexception);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
+ private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("%[0-9]+\\$s"); // Scissors
|
||||||
|
|
||||||
|
public Serializer() {}
|
||||||
|
|
||||||
|
- public MutableComponent deserialize(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException {
|
||||||
|
+ // Scissors start
|
||||||
|
+ private MutableComponent deserialize(JsonElement jsonelement, JsonDeserializationContext jsondeserializationcontext, int depth) throws JsonParseException {
|
||||||
|
+ if (depth > ScissorsConfig.componentDepthLimit) {
|
||||||
|
+ throw new JsonParseException("Depth limit exceeded");
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (jsonelement.isJsonPrimitive()) {
|
||||||
|
return Component.literal(jsonelement.getAsString());
|
||||||
|
} else {
|
||||||
|
@@ -266,18 +274,16 @@ public interface Component extends Message, FormattedText, Iterable<Component> {
|
||||||
|
if (!jsonelement.isJsonObject()) {
|
||||||
|
if (jsonelement.isJsonArray()) {
|
||||||
|
JsonArray jsonarray = jsonelement.getAsJsonArray();
|
||||||
|
- // Scissors start
|
||||||
|
if (jsonarray.size() <= 0) {
|
||||||
|
throw new JsonParseException("Unexpected empty array of components");
|
||||||
|
}
|
||||||
|
- // Scissors end
|
||||||
|
|
||||||
|
ichatmutablecomponent = null;
|
||||||
|
Iterator iterator = jsonarray.iterator();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
JsonElement jsonelement1 = (JsonElement) iterator.next();
|
||||||
|
- MutableComponent ichatmutablecomponent1 = this.deserialize(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext);
|
||||||
|
+ MutableComponent ichatmutablecomponent1 = this.deserialize(jsonelement1, jsondeserializationcontext, depth + 1);
|
||||||
|
|
||||||
|
if (ichatmutablecomponent == null) {
|
||||||
|
ichatmutablecomponent = ichatmutablecomponent1;
|
||||||
|
@@ -301,12 +307,17 @@ public interface Component extends Message, FormattedText, Iterable<Component> {
|
||||||
|
s = GsonHelper.getAsString(jsonobject, "translate");
|
||||||
|
String s1 = GsonHelper.getAsString(jsonobject, "fallback", (String) null);
|
||||||
|
|
||||||
|
+ // Penalize depth for placeholders in translate & fallback
|
||||||
|
+ long translate_placeholders = PLACEHOLDER_PATTERN.matcher(s).results().count();
|
||||||
|
+ long fallback_placeholders = s1 != null ? PLACEHOLDER_PATTERN.matcher(s1).results().count() : 0;
|
||||||
|
+ int penalty = (int)Math.max(translate_placeholders, fallback_placeholders) * 12;
|
||||||
|
+
|
||||||
|
if (jsonobject.has("with")) {
|
||||||
|
JsonArray jsonarray1 = GsonHelper.getAsJsonArray(jsonobject, "with");
|
||||||
|
Object[] aobject = new Object[jsonarray1.size()];
|
||||||
|
|
||||||
|
for (int i = 0; i < aobject.length; ++i) {
|
||||||
|
- aobject[i] = Serializer.unwrapTextArgument(this.deserialize(jsonarray1.get(i), type, jsondeserializationcontext));
|
||||||
|
+ aobject[i] = Serializer.unwrapTextArgument(this.deserialize(jsonarray1.get(i), jsondeserializationcontext, depth + 1 + penalty));
|
||||||
|
}
|
||||||
|
|
||||||
|
ichatmutablecomponent = Component.translatableWithFallback(s, s1, aobject);
|
||||||
|
@@ -322,7 +333,7 @@ public interface Component extends Message, FormattedText, Iterable<Component> {
|
||||||
|
|
||||||
|
ichatmutablecomponent = Component.score(GsonHelper.getAsString(jsonobject1, "name"), GsonHelper.getAsString(jsonobject1, "objective"));
|
||||||
|
} else if (jsonobject.has("selector")) {
|
||||||
|
- Optional<Component> optional = this.parseSeparator(type, jsondeserializationcontext, jsonobject);
|
||||||
|
+ Optional<Component> optional = this.parseSeparator(jsondeserializationcontext, jsonobject, depth + 1);
|
||||||
|
|
||||||
|
ichatmutablecomponent = Component.selector(GsonHelper.getAsString(jsonobject, "selector"), optional);
|
||||||
|
} else if (jsonobject.has("keybind")) {
|
||||||
|
@@ -333,7 +344,7 @@ public interface Component extends Message, FormattedText, Iterable<Component> {
|
||||||
|
}
|
||||||
|
|
||||||
|
s = GsonHelper.getAsString(jsonobject, "nbt");
|
||||||
|
- Optional<Component> optional1 = this.parseSeparator(type, jsondeserializationcontext, jsonobject);
|
||||||
|
+ Optional<Component> optional1 = this.parseSeparator(jsondeserializationcontext, jsonobject, depth + 1);
|
||||||
|
boolean flag = GsonHelper.getAsBoolean(jsonobject, "interpret", false);
|
||||||
|
Object object;
|
||||||
|
|
||||||
|
@@ -360,7 +371,7 @@ public interface Component extends Message, FormattedText, Iterable<Component> {
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < jsonarray2.size(); ++j) {
|
||||||
|
- ichatmutablecomponent.append((Component) this.deserialize(jsonarray2.get(j), type, jsondeserializationcontext));
|
||||||
|
+ ichatmutablecomponent.append((Component) this.deserialize(jsonarray2.get(j), jsondeserializationcontext, depth + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -370,6 +381,11 @@ public interface Component extends Message, FormattedText, Iterable<Component> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ public MutableComponent deserialize(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException {
|
||||||
|
+ return this.deserialize(jsonelement, jsondeserializationcontext, 1);
|
||||||
|
+ }
|
||||||
|
+ // Scissors end
|
||||||
|
+
|
||||||
|
private static Object unwrapTextArgument(Object text) {
|
||||||
|
if (text instanceof Component) {
|
||||||
|
Component ichatbasecomponent = (Component) text;
|
||||||
|
@@ -388,8 +404,10 @@ public interface Component extends Message, FormattedText, Iterable<Component> {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
- private Optional<Component> parseSeparator(Type type, JsonDeserializationContext context, JsonObject json) {
|
||||||
|
- return json.has("separator") ? Optional.of(this.deserialize(json.get("separator"), type, context)) : Optional.empty();
|
||||||
|
+ // Scissors start
|
||||||
|
+ private Optional<Component> parseSeparator(JsonDeserializationContext context, JsonObject json, int depth) {
|
||||||
|
+ return json.has("separator") ? Optional.of(this.deserialize(json.get("separator"), context, depth + 1)) : Optional.empty();
|
||||||
|
+ // Scissors end
|
||||||
|
}
|
||||||
|
|
||||||
|
private void serializeStyle(Style style, JsonObject json, JsonSerializationContext context) {
|
Loading…
Reference in a new issue