From df2a849adceb04cad9131d257c452b9dcd7ea849 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Sun, 14 Jun 2026 15:59:56 +0200 Subject: [PATCH] fix(rooms): bound rights removal batches --- .../users/RoomUserRemoveRightsEvent.java | 9 ++++++ .../RoomUserRemoveRightsContractTest.java | 32 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 Emulator/src/test/java/com/eu/habbo/messages/incoming/rooms/users/RoomUserRemoveRightsContractTest.java diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/users/RoomUserRemoveRightsEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/users/RoomUserRemoveRightsEvent.java index cc03c734..987ec101 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/users/RoomUserRemoveRightsEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/users/RoomUserRemoveRightsEvent.java @@ -3,8 +3,12 @@ package com.eu.habbo.messages.incoming.rooms.users; import com.eu.habbo.habbohotel.permissions.Permission; import com.eu.habbo.habbohotel.rooms.Room; import com.eu.habbo.messages.incoming.MessageHandler; +import com.eu.habbo.util.PacketGuard; public class RoomUserRemoveRightsEvent extends MessageHandler { + private static final int MAX_RIGHTS_REMOVALS = 100; + private static final int BYTES_PER_USER_ID = 4; + @Override public void handle() throws Exception { int amount = this.packet.readInt(); @@ -15,6 +19,11 @@ public class RoomUserRemoveRightsEvent extends MessageHandler { return; if (room.getOwnerId() == this.client.getHabbo().getHabboInfo().getId() || this.client.getHabbo().hasPermission(Permission.ACC_ANYROOMOWNER)) { + if (!PacketGuard.isCountInRange(amount, 1, MAX_RIGHTS_REMOVALS) + || !PacketGuard.hasFixedWidthEntries(this.packet, amount, BYTES_PER_USER_ID)) { + return; + } + for (int i = 0; i < amount; i++) { int userId = this.packet.readInt(); diff --git a/Emulator/src/test/java/com/eu/habbo/messages/incoming/rooms/users/RoomUserRemoveRightsContractTest.java b/Emulator/src/test/java/com/eu/habbo/messages/incoming/rooms/users/RoomUserRemoveRightsContractTest.java new file mode 100644 index 00000000..22b5c09c --- /dev/null +++ b/Emulator/src/test/java/com/eu/habbo/messages/incoming/rooms/users/RoomUserRemoveRightsContractTest.java @@ -0,0 +1,32 @@ +package com.eu.habbo.messages.incoming.rooms.users; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.junit.jupiter.api.Test; + +class RoomUserRemoveRightsContractTest { + private static final Path SOURCE = Path.of( + "src/main/java/com/eu/habbo/messages/incoming/rooms/users/RoomUserRemoveRightsEvent.java"); + + @Test + void removeRightsBatchIsBoundedAndRequiresCompletePayload() throws IOException { + String source = Files.readString(SOURCE); + + assertTrue(source.contains("private static final int MAX_RIGHTS_REMOVALS = 100;")); + assertTrue(source.contains("PacketGuard.isCountInRange(amount, 1, MAX_RIGHTS_REMOVALS)")); + assertTrue(source.contains("PacketGuard.hasFixedWidthEntries(this.packet, amount, BYTES_PER_USER_ID)")); + + int guardIndex = source.indexOf("PacketGuard.isCountInRange(amount, 1, MAX_RIGHTS_REMOVALS)"); + int payloadIndex = source.indexOf("PacketGuard.hasFixedWidthEntries(this.packet, amount, BYTES_PER_USER_ID)"); + int readIndex = source.indexOf("int userId = this.packet.readInt();"); + int removeIndex = source.indexOf("room.removeRights(userId);"); + + assertTrue(guardIndex < readIndex, "batch size should be validated before reading user ids"); + assertTrue(payloadIndex < readIndex, "payload length should be validated before reading user ids"); + assertTrue(readIndex < removeIndex, "rights should only be removed after reading a validated user id"); + } +}