mirror of
https://github.com/Minestom/Minestom.git
synced 2024-06-25 05:54:53 +02:00
fix: require size when reading collection to prevent oom. Do not allow string longer than remaining bytes
This commit is contained in:
parent
d86b890cc6
commit
fb7e4b10e0
|
@ -8,12 +8,14 @@ import java.util.List;
|
|||
import static net.minestom.server.network.NetworkBuffer.STRING;
|
||||
|
||||
public record ArgumentSignatures(@NotNull List<@NotNull Entry> entries) implements NetworkBuffer.Writer {
|
||||
public static final int MAX_ENTRIES = 8;
|
||||
|
||||
public ArgumentSignatures {
|
||||
entries = List.copyOf(entries);
|
||||
}
|
||||
|
||||
public ArgumentSignatures(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readCollection(Entry::new));
|
||||
this(reader.readCollection(Entry::new, MAX_ENTRIES));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,12 +9,14 @@ import java.util.List;
|
|||
import static net.minestom.server.network.NetworkBuffer.VAR_INT;
|
||||
|
||||
public record LastSeenMessages(@NotNull List<@NotNull MessageSignature> entries) implements NetworkBuffer.Writer {
|
||||
public static final int MAX_ENTRIES = 20;
|
||||
|
||||
public LastSeenMessages {
|
||||
entries = List.copyOf(entries);
|
||||
}
|
||||
|
||||
public LastSeenMessages(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readCollection(MessageSignature::new));
|
||||
this(reader.readCollection(MessageSignature::new, MAX_ENTRIES));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,7 +27,7 @@ public record LastSeenMessages(@NotNull List<@NotNull MessageSignature> entries)
|
|||
public static final Packed EMPTY = new Packed(List.of());
|
||||
|
||||
public Packed(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readCollection(MessageSignature.Packed::new));
|
||||
this(reader.readCollection(MessageSignature.Packed::new, MAX_ENTRIES));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
package net.minestom.server.network;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.Collection;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.entity.Entity;
|
||||
|
@ -18,6 +10,7 @@ import net.minestom.server.item.ItemStack;
|
|||
import net.minestom.server.network.packet.server.play.data.DeathLocation;
|
||||
import net.minestom.server.utils.Direction;
|
||||
import net.minestom.server.utils.Either;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -27,6 +20,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTWriter;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
@ -176,8 +170,9 @@ public final class NetworkBuffer {
|
|||
}
|
||||
}
|
||||
|
||||
public <T> @NotNull List<@NotNull T> readCollection(@NotNull Type<T> type) {
|
||||
public <T> @NotNull List<@NotNull T> readCollection(@NotNull Type<T> type, int maxSize) {
|
||||
final int size = read(VAR_INT);
|
||||
Check.argCondition(size > maxSize, "Collection size (" + size + ") is higher than the maximum allowed size (" + maxSize + ")");
|
||||
final List<T> values = new java.util.ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
values.add(read(type));
|
||||
|
@ -185,8 +180,9 @@ public final class NetworkBuffer {
|
|||
return values;
|
||||
}
|
||||
|
||||
public <T> @NotNull List<@NotNull T> readCollection(@NotNull Function<@NotNull NetworkBuffer, @NotNull T> function) {
|
||||
public <T> @NotNull List<@NotNull T> readCollection(@NotNull Function<@NotNull NetworkBuffer, @NotNull T> function, int maxSize) {
|
||||
final int size = read(VAR_INT);
|
||||
Check.argCondition(size > maxSize, "Collection size (" + size + ") is higher than the maximum allowed size (" + maxSize + ")");
|
||||
final List<T> values = new java.util.ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
values.add(function.apply(this));
|
||||
|
|
|
@ -13,6 +13,7 @@ import net.minestom.server.item.ItemStack;
|
|||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.network.packet.server.play.data.DeathLocation;
|
||||
import net.minestom.server.utils.Direction;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
import org.jglrxavpok.hephaistos.nbt.*;
|
||||
|
@ -219,6 +220,8 @@ final class NetworkBufferTypes {
|
|||
},
|
||||
buffer -> {
|
||||
final int length = buffer.read(VAR_INT);
|
||||
final int remaining = buffer.nioBuffer.limit() - buffer.readIndex();
|
||||
Check.argCondition(length > remaining, "String is too long (length: " + length + ", readable: " + remaining + ")");
|
||||
byte[] bytes = new byte[length];
|
||||
buffer.nioBuffer.get(buffer.readIndex(), bytes);
|
||||
buffer.readIndex += length;
|
||||
|
|
|
@ -13,6 +13,8 @@ public record ClientClickWindowPacket(byte windowId, int stateId,
|
|||
short slot, byte button, @NotNull ClickType clickType,
|
||||
@NotNull List<ChangedSlot> changedSlots,
|
||||
@NotNull ItemStack clickedItem) implements ClientPacket {
|
||||
public static final int MAX_CHANGED_SLOTS = 128;
|
||||
|
||||
public ClientClickWindowPacket {
|
||||
changedSlots = List.copyOf(changedSlots);
|
||||
}
|
||||
|
@ -20,7 +22,7 @@ public record ClientClickWindowPacket(byte windowId, int stateId,
|
|||
public ClientClickWindowPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(BYTE), reader.read(VAR_INT),
|
||||
reader.read(SHORT), reader.read(BYTE), reader.readEnum(ClickType.class),
|
||||
reader.readCollection(ChangedSlot::new), reader.read(ITEM));
|
||||
reader.readCollection(ChangedSlot::new, MAX_CHANGED_SLOTS), reader.read(ITEM));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -12,6 +12,8 @@ import static net.minestom.server.network.NetworkBuffer.VAR_INT;
|
|||
|
||||
public record ClientEditBookPacket(int slot, @NotNull List<String> pages,
|
||||
@Nullable String title) implements ClientPacket {
|
||||
public static final int MAX_PAGES = 200;
|
||||
|
||||
public ClientEditBookPacket {
|
||||
pages = List.copyOf(pages);
|
||||
if (title != null && title.length() > 128) {
|
||||
|
@ -20,7 +22,7 @@ public record ClientEditBookPacket(int slot, @NotNull List<String> pages,
|
|||
}
|
||||
|
||||
public ClientEditBookPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(VAR_INT), reader.readCollection(STRING),
|
||||
this(reader.read(VAR_INT), reader.readCollection(STRING, MAX_PAGES),
|
||||
reader.readOptional(STRING));
|
||||
}
|
||||
|
||||
|
|
|
@ -13,9 +13,10 @@ import java.util.Set;
|
|||
import static net.minestom.server.network.NetworkBuffer.STRING;
|
||||
|
||||
public record UpdateEnabledFeaturesPacket(@NotNull Set<NamespaceID> features) implements ServerPacket {
|
||||
public static final int MAX_FEATURES = 1024;
|
||||
|
||||
public UpdateEnabledFeaturesPacket(@NotNull NetworkBuffer buffer) {
|
||||
this(Set.copyOf(buffer.readCollection((b) -> NamespaceID.from(b.read(STRING)))));
|
||||
this(Set.copyOf(buffer.readCollection((b) -> NamespaceID.from(b.read(STRING)), MAX_FEATURES)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -24,6 +24,8 @@ import static net.minestom.server.network.NetworkBuffer.*;
|
|||
public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping> advancementMappings,
|
||||
@NotNull List<String> identifiersToRemove,
|
||||
@NotNull List<ProgressMapping> progressMappings) implements ComponentHoldingServerPacket {
|
||||
public static final int MAX_ADVANCEMENTS = Short.MAX_VALUE;
|
||||
|
||||
public AdvancementsPacket {
|
||||
advancementMappings = List.copyOf(advancementMappings);
|
||||
identifiersToRemove = List.copyOf(identifiersToRemove);
|
||||
|
@ -31,9 +33,9 @@ public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping
|
|||
}
|
||||
|
||||
public AdvancementsPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(BOOLEAN), reader.readCollection(AdvancementMapping::new),
|
||||
reader.readCollection(STRING),
|
||||
reader.readCollection(ProgressMapping::new));
|
||||
this(reader.read(BOOLEAN), reader.readCollection(AdvancementMapping::new, MAX_ADVANCEMENTS),
|
||||
reader.readCollection(STRING, MAX_ADVANCEMENTS),
|
||||
reader.readCollection(ProgressMapping::new, MAX_ADVANCEMENTS));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -112,7 +114,7 @@ public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping
|
|||
|
||||
public Advancement(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readOptional(STRING), reader.readOptional(DisplayData::new),
|
||||
reader.readCollection(Requirement::new), reader.read(BOOLEAN));
|
||||
reader.readCollection(Requirement::new, MAX_ADVANCEMENTS), reader.read(BOOLEAN));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -140,7 +142,7 @@ public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping
|
|||
}
|
||||
|
||||
public Requirement(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readCollection(STRING));
|
||||
this(reader.readCollection(STRING, MAX_ADVANCEMENTS));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -224,7 +226,7 @@ public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping
|
|||
}
|
||||
|
||||
public AdvancementProgress(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readCollection(Criteria::new));
|
||||
this(reader.readCollection(Criteria::new, MAX_ADVANCEMENTS));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,12 +13,14 @@ import static net.minestom.server.network.NetworkBuffer.STRING;
|
|||
|
||||
public record CustomChatCompletionPacket(@NotNull Action action,
|
||||
@NotNull List<@NotNull String> entries) implements ServerPacket {
|
||||
public static final int MAX_ENTRIES = Short.MAX_VALUE;
|
||||
|
||||
public CustomChatCompletionPacket {
|
||||
entries = List.copyOf(entries);
|
||||
}
|
||||
|
||||
public CustomChatCompletionPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readEnum(Action.class), reader.readCollection(STRING));
|
||||
this(reader.readEnum(Action.class), reader.readCollection(STRING, MAX_ENTRIES));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,6 +16,8 @@ import static net.minestom.server.network.NetworkBuffer.*;
|
|||
|
||||
public record DeclareCommandsPacket(@NotNull List<Node> nodes,
|
||||
int rootIndex) implements ServerPacket {
|
||||
public static final int MAX_NODES = Short.MAX_VALUE;
|
||||
|
||||
public DeclareCommandsPacket {
|
||||
nodes = List.copyOf(nodes);
|
||||
}
|
||||
|
@ -25,7 +27,7 @@ public record DeclareCommandsPacket(@NotNull List<Node> nodes,
|
|||
Node node = new Node();
|
||||
node.read(r);
|
||||
return node;
|
||||
}), reader.read(VAR_INT));
|
||||
}, MAX_NODES), reader.read(VAR_INT));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,6 +16,9 @@ import java.util.List;
|
|||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
public record DeclareRecipesPacket(@NotNull List<DeclaredRecipe> recipes) implements ServerPacket {
|
||||
public static final int MAX_RECIPES = Short.MAX_VALUE;
|
||||
public static final int MAX_INGREDIENTS = 128;
|
||||
|
||||
public DeclareRecipesPacket {
|
||||
recipes = List.copyOf(recipes);
|
||||
}
|
||||
|
@ -35,7 +38,7 @@ public record DeclareRecipesPacket(@NotNull List<DeclaredRecipe> recipes) implem
|
|||
case "smithing_transform" -> new DeclaredSmithingTransformRecipe(reader);
|
||||
default -> throw new UnsupportedOperationException("Unrecognized type: " + type);
|
||||
};
|
||||
}));
|
||||
}, MAX_RECIPES));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -72,7 +75,7 @@ public record DeclareRecipesPacket(@NotNull List<DeclaredRecipe> recipes) implem
|
|||
private DeclaredShapelessCraftingRecipe(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(STRING), reader.read(STRING),
|
||||
reader.readEnum(RecipeCategory.Crafting.class),
|
||||
reader.readCollection(Ingredient::new), reader.read(ITEM));
|
||||
reader.readCollection(Ingredient::new, MAX_INGREDIENTS), reader.read(ITEM));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -314,7 +317,7 @@ public record DeclareRecipesPacket(@NotNull List<DeclaredRecipe> recipes) implem
|
|||
}
|
||||
|
||||
public Ingredient(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readCollection(ITEM));
|
||||
this(reader.readCollection(ITEM, MAX_INGREDIENTS));
|
||||
}
|
||||
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
|
|
|
@ -12,6 +12,8 @@ import java.util.List;
|
|||
import static net.minestom.server.network.NetworkBuffer.VAR_INT;
|
||||
|
||||
public record DestroyEntitiesPacket(@NotNull List<Integer> entityIds) implements ServerPacket {
|
||||
public static final int MAX_ENTRIES = Short.MAX_VALUE;
|
||||
|
||||
public DestroyEntitiesPacket {
|
||||
entityIds = List.copyOf(entityIds);
|
||||
}
|
||||
|
@ -21,7 +23,7 @@ public record DestroyEntitiesPacket(@NotNull List<Integer> entityIds) implements
|
|||
}
|
||||
|
||||
public DestroyEntitiesPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readCollection(VAR_INT));
|
||||
this(reader.readCollection(VAR_INT, MAX_ENTRIES));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,6 +17,8 @@ import java.util.List;
|
|||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
public record EntityPropertiesPacket(int entityId, List<AttributeInstance> properties) implements ServerPacket {
|
||||
public static final int MAX_ENTRIES = 1024;
|
||||
|
||||
public EntityPropertiesPacket {
|
||||
properties = List.copyOf(properties);
|
||||
}
|
||||
|
@ -32,7 +34,7 @@ public record EntityPropertiesPacket(int entityId, List<AttributeInstance> prope
|
|||
instance.addModifier(modifier);
|
||||
}
|
||||
return instance;
|
||||
}));
|
||||
}, MAX_ENTRIES));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,7 +9,6 @@ import net.minestom.server.network.packet.server.play.data.DeathLocation;
|
|||
import net.minestom.server.utils.PacketUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -22,6 +21,8 @@ public record JoinGamePacket(
|
|||
String dimensionType, String world, long hashedSeed, GameMode gameMode, GameMode previousGameMode,
|
||||
boolean isDebug, boolean isFlat, DeathLocation deathLocation, int portalCooldown
|
||||
) implements ServerPacket {
|
||||
public static final int MAX_WORLDS = Short.MAX_VALUE;
|
||||
|
||||
public JoinGamePacket {
|
||||
worlds = List.copyOf(worlds);
|
||||
}
|
||||
|
@ -30,7 +31,7 @@ public record JoinGamePacket(
|
|||
this(
|
||||
reader.read(INT),
|
||||
reader.read(BOOLEAN),
|
||||
reader.readCollection(STRING),
|
||||
reader.readCollection(STRING, MAX_WORLDS),
|
||||
reader.read(VAR_INT),
|
||||
reader.read(VAR_INT),
|
||||
reader.read(VAR_INT),
|
||||
|
|
|
@ -16,6 +16,8 @@ import static net.minestom.server.network.NetworkBuffer.*;
|
|||
public record MapDataPacket(int mapId, byte scale, boolean locked,
|
||||
boolean trackingPosition, @NotNull List<Icon> icons,
|
||||
@Nullable MapDataPacket.ColorContent colorContent) implements ServerPacket {
|
||||
public static final int MAX_ICONS = 1024;
|
||||
|
||||
public MapDataPacket {
|
||||
icons = List.copyOf(icons);
|
||||
}
|
||||
|
@ -35,7 +37,7 @@ public record MapDataPacket(int mapId, byte scale, boolean locked,
|
|||
var scale = reader.read(BYTE);
|
||||
var locked = reader.read(BOOLEAN);
|
||||
var trackingPosition = reader.read(BOOLEAN);
|
||||
List<Icon> icons = trackingPosition ? reader.readCollection(Icon::new) : List.of();
|
||||
List<Icon> icons = trackingPosition ? reader.readCollection(Icon::new, MAX_ICONS) : List.of();
|
||||
|
||||
var columns = reader.read(BYTE);
|
||||
if (columns <= 0) return new MapDataPacket(mapId, scale, locked, trackingPosition, icons, null);
|
||||
|
|
|
@ -11,6 +11,8 @@ import java.util.List;
|
|||
import java.util.UUID;
|
||||
|
||||
public record PlayerInfoRemovePacket(@NotNull List<@NotNull UUID> uuids) implements ServerPacket {
|
||||
public static final int MAX_ENTRIES = 1024;
|
||||
|
||||
public PlayerInfoRemovePacket(@NotNull UUID uuid) {
|
||||
this(List.of(uuid));
|
||||
}
|
||||
|
@ -20,7 +22,7 @@ public record PlayerInfoRemovePacket(@NotNull List<@NotNull UUID> uuids) impleme
|
|||
}
|
||||
|
||||
public PlayerInfoRemovePacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readCollection(NetworkBuffer.UUID));
|
||||
this(reader.readCollection(NetworkBuffer.UUID, MAX_ENTRIES));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,6 +7,7 @@ import net.minestom.server.network.ConnectionState;
|
|||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import net.minestom.server.network.player.GameProfile;
|
||||
import net.minestom.server.utils.PacketUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -19,6 +20,8 @@ import java.util.UUID;
|
|||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
public final class PlayerInfoUpdatePacket implements ServerPacket {
|
||||
public static final int MAX_ENTRIES = 1024;
|
||||
|
||||
private final @NotNull EnumSet<@NotNull Action> actions;
|
||||
private final @NotNull List<@NotNull Entry> entries;
|
||||
|
||||
|
@ -47,7 +50,7 @@ public final class PlayerInfoUpdatePacket implements ServerPacket {
|
|||
switch (action) {
|
||||
case ADD_PLAYER -> {
|
||||
username = reader.read(STRING);
|
||||
properties = reader.readCollection(Property::new);
|
||||
properties = reader.readCollection(Property::new, GameProfile.MAX_PROPERTIES);
|
||||
}
|
||||
case INITIALIZE_CHAT -> chatSession = new ChatSession(reader);
|
||||
case UPDATE_GAME_MODE -> gameMode = reader.readEnum(GameMode.class);
|
||||
|
@ -57,7 +60,7 @@ public final class PlayerInfoUpdatePacket implements ServerPacket {
|
|||
}
|
||||
}
|
||||
return new Entry(uuid, username, properties, listed, latency, gameMode, displayName, chatSession);
|
||||
});
|
||||
}, MAX_ENTRIES);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,12 +13,14 @@ import static net.minestom.server.network.NetworkBuffer.VAR_INT;
|
|||
|
||||
public record SetPassengersPacket(int vehicleEntityId,
|
||||
@NotNull List<Integer> passengersId) implements ServerPacket {
|
||||
public static final int MAX_PASSENGERS = 16384;
|
||||
|
||||
public SetPassengersPacket {
|
||||
passengersId = List.copyOf(passengersId);
|
||||
}
|
||||
|
||||
public SetPassengersPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(VAR_INT), reader.readCollection(VAR_INT));
|
||||
this(reader.read(VAR_INT), reader.readCollection(VAR_INT, MAX_PASSENGERS));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,12 +13,14 @@ import java.util.List;
|
|||
import static net.minestom.server.network.NetworkBuffer.VAR_INT;
|
||||
|
||||
public record StatisticsPacket(@NotNull List<Statistic> statistics) implements ServerPacket {
|
||||
public static final int MAX_ENTRIES = 16384;
|
||||
|
||||
public StatisticsPacket {
|
||||
statistics = List.copyOf(statistics);
|
||||
}
|
||||
|
||||
public StatisticsPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readCollection(Statistic::new));
|
||||
this(reader.readCollection(Statistic::new, MAX_ENTRIES));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,12 +20,14 @@ import static net.minestom.server.network.NetworkBuffer.*;
|
|||
|
||||
public record TabCompletePacket(int transactionId, int start, int length,
|
||||
@NotNull List<Match> matches) implements ComponentHoldingServerPacket {
|
||||
public static final int MAX_ENTRIES = Short.MAX_VALUE;
|
||||
|
||||
public TabCompletePacket {
|
||||
matches = List.copyOf(matches);
|
||||
}
|
||||
|
||||
public TabCompletePacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(VAR_INT), reader.read(VAR_INT), reader.read(VAR_INT), reader.readCollection(Match::new));
|
||||
this(reader.read(VAR_INT), reader.read(VAR_INT), reader.read(VAR_INT), reader.readCollection(Match::new, MAX_ENTRIES));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,6 +23,8 @@ import static net.minestom.server.network.NetworkBuffer.*;
|
|||
* The packet creates or updates teams
|
||||
*/
|
||||
public record TeamsPacket(String teamName, Action action) implements ComponentHoldingServerPacket {
|
||||
public static final int MAX_MEMBERS = 16384;
|
||||
|
||||
public TeamsPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(STRING), switch (reader.read(BYTE)) {
|
||||
case 0 -> new CreateTeamAction(reader);
|
||||
|
@ -73,7 +75,7 @@ public record TeamsPacket(String teamName, Action action) implements ComponentHo
|
|||
this(reader.read(COMPONENT), reader.read(BYTE),
|
||||
NameTagVisibility.fromIdentifier(reader.read(STRING)), CollisionRule.fromIdentifier(reader.read(STRING)),
|
||||
NamedTextColor.namedColor(reader.read(VAR_INT)), reader.read(COMPONENT), reader.read(COMPONENT),
|
||||
reader.readCollection(STRING));
|
||||
reader.readCollection(STRING, MAX_MEMBERS));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -178,7 +180,7 @@ public record TeamsPacket(String teamName, Action action) implements ComponentHo
|
|||
}
|
||||
|
||||
public AddEntitiesToTeamAction(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readCollection(STRING));
|
||||
this(reader.readCollection(STRING, MAX_MEMBERS));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -198,7 +200,7 @@ public record TeamsPacket(String teamName, Action action) implements ComponentHo
|
|||
}
|
||||
|
||||
public RemoveEntitiesToTeamAction(@NotNull NetworkBuffer reader) {
|
||||
this(reader.readCollection(STRING));
|
||||
this(reader.readCollection(STRING, MAX_MEMBERS));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,12 +15,14 @@ import static net.minestom.server.network.NetworkBuffer.*;
|
|||
public record TradeListPacket(int windowId, @NotNull List<Trade> trades,
|
||||
int villagerLevel, int experience,
|
||||
boolean regularVillager, boolean canRestock) implements ServerPacket {
|
||||
public static final int MAX_TRADES = Short.MAX_VALUE;
|
||||
|
||||
public TradeListPacket {
|
||||
trades = List.copyOf(trades);
|
||||
}
|
||||
|
||||
public TradeListPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(VAR_INT), reader.readCollection(Trade::new),
|
||||
this(reader.read(VAR_INT), reader.readCollection(Trade::new, MAX_TRADES),
|
||||
reader.read(VAR_INT), reader.read(VAR_INT),
|
||||
reader.read(BOOLEAN), reader.read(BOOLEAN));
|
||||
}
|
||||
|
|
|
@ -49,8 +49,8 @@ public record UnlockRecipesPacket(int mode,
|
|||
var blastFurnaceRecipeBookFilterActive = reader.read(BOOLEAN);
|
||||
var smokerRecipeBookOpen = reader.read(BOOLEAN);
|
||||
var smokerRecipeBookFilterActive = reader.read(BOOLEAN);
|
||||
var recipeIds = reader.readCollection(STRING);
|
||||
var initRecipeIds = mode == 0 ? reader.readCollection(STRING) : null;
|
||||
var recipeIds = reader.readCollection(STRING, DeclareRecipesPacket.MAX_RECIPES);
|
||||
var initRecipeIds = mode == 0 ? reader.readCollection(STRING, DeclareRecipesPacket.MAX_RECIPES) : null;
|
||||
return new UnlockRecipesPacket(mode,
|
||||
craftingRecipeBookOpen, craftingRecipeBookFilterActive,
|
||||
smeltingRecipeBookOpen, smeltingRecipeBookFilterActive,
|
||||
|
|
|
@ -19,12 +19,14 @@ import static net.minestom.server.network.NetworkBuffer.*;
|
|||
|
||||
public record WindowItemsPacket(byte windowId, int stateId, @NotNull List<ItemStack> items,
|
||||
@NotNull ItemStack carriedItem) implements ComponentHoldingServerPacket {
|
||||
public static final int MAX_ENTRIES = 128;
|
||||
|
||||
public WindowItemsPacket {
|
||||
items = List.copyOf(items);
|
||||
}
|
||||
|
||||
public WindowItemsPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(BYTE), reader.read(VAR_INT), reader.readCollection(ITEM),
|
||||
this(reader.read(BYTE), reader.read(VAR_INT), reader.readCollection(ITEM, MAX_ENTRIES),
|
||||
reader.read(ITEM));
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@ import org.jetbrains.annotations.NotNull;
|
|||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
import static net.minestom.server.network.NetworkBuffer.BYTE_ARRAY;
|
||||
import static net.minestom.server.network.NetworkBuffer.LONG_ARRAY;
|
||||
|
||||
public record LightData(
|
||||
@NotNull BitSet skyMask, @NotNull BitSet blockMask,
|
||||
|
@ -14,11 +15,13 @@ public record LightData(
|
|||
@NotNull List<byte[]> skyLight,
|
||||
@NotNull List<byte[]> blockLight
|
||||
) implements NetworkBuffer.Writer {
|
||||
public static final int MAX_SECTIONS = 4096 / 16;
|
||||
|
||||
public LightData(@NotNull NetworkBuffer reader) {
|
||||
this(
|
||||
BitSet.valueOf(reader.read(LONG_ARRAY)), BitSet.valueOf(reader.read(LONG_ARRAY)),
|
||||
BitSet.valueOf(reader.read(LONG_ARRAY)), BitSet.valueOf(reader.read(LONG_ARRAY)),
|
||||
reader.readCollection(BYTE_ARRAY), reader.readCollection(BYTE_ARRAY)
|
||||
reader.readCollection(BYTE_ARRAY, MAX_SECTIONS), reader.readCollection(BYTE_ARRAY, MAX_SECTIONS)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ import static net.minestom.server.network.NetworkBuffer.STRING;
|
|||
@ApiStatus.Experimental
|
||||
public record GameProfile(@NotNull UUID uuid, @NotNull String name,
|
||||
@NotNull List<@NotNull Property> properties) implements NetworkBuffer.Writer {
|
||||
public static final int MAX_PROPERTIES = 1024;
|
||||
|
||||
public GameProfile {
|
||||
if (name.isBlank())
|
||||
throw new IllegalArgumentException("Name cannot be blank");
|
||||
|
@ -22,7 +24,7 @@ public record GameProfile(@NotNull UUID uuid, @NotNull String name,
|
|||
}
|
||||
|
||||
public GameProfile(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(NetworkBuffer.UUID), reader.read(STRING), reader.readCollection(Property::new));
|
||||
this(reader.read(NetworkBuffer.UUID), reader.read(STRING), reader.readCollection(Property::new, MAX_PROPERTIES));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,12 +8,12 @@ import org.jetbrains.annotations.Nullable;
|
|||
import org.jetbrains.annotations.UnknownNullability;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class NetworkBufferTest {
|
||||
|
||||
|
@ -271,6 +271,28 @@ public class NetworkBufferTest {
|
|||
assertBufferTypeCollection(BOOLEAN, List.of(true), new byte[]{0x01, 0x01});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectionMaxSize() {
|
||||
var buffer = new NetworkBuffer();
|
||||
var list = new ArrayList<Boolean>();
|
||||
for (int i = 0; i < 1000; i++)
|
||||
list.add(true);
|
||||
buffer.writeCollection(BOOLEAN, list);
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> buffer.readCollection(BOOLEAN, 10));
|
||||
buffer.readIndex(0); // reset
|
||||
assertThrows(IllegalArgumentException.class, () -> buffer.readCollection(b -> b.read(BOOLEAN), 10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oomStringRegression() {
|
||||
var buffer = new NetworkBuffer(ByteBuffer.allocate(100));
|
||||
buffer.write(VAR_INT, Integer.MAX_VALUE); // String length
|
||||
buffer.write(RAW_BYTES, "Hello".getBytes(StandardCharsets.UTF_8)); // String data
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> buffer.read(STRING)); // oom
|
||||
}
|
||||
|
||||
static <T> void assertBufferType(NetworkBuffer.@NotNull Type<T> type, @UnknownNullability T value, byte[] expected, @NotNull Action<T> action) {
|
||||
var buffer = new NetworkBuffer();
|
||||
action.write(buffer, type, value);
|
||||
|
@ -346,7 +368,7 @@ public class NetworkBufferTest {
|
|||
assertEquals(0, buffer.readIndex());
|
||||
if (expected != null) assertEquals(expected.length, buffer.writeIndex());
|
||||
|
||||
var actual = buffer.readCollection(type);
|
||||
var actual = buffer.readCollection(type, Integer.MAX_VALUE);
|
||||
|
||||
assertEquals(values, actual);
|
||||
if (expected != null) assertEquals(expected.length, buffer.readIndex());
|
||||
|
|
Loading…
Reference in New Issue
Block a user