diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/RoomSettingsInputGuard.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/RoomSettingsInputGuard.java new file mode 100644 index 00000000..e3a65dfe --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/RoomSettingsInputGuard.java @@ -0,0 +1,74 @@ +package com.eu.habbo.messages.incoming.rooms; + +import com.eu.habbo.habbohotel.rooms.RoomState; + +final class RoomSettingsInputGuard { + static final int MAX_PASSWORD_LENGTH = 64; + static final int MAX_TAGS = 2; + static final int MIN_USERS_MAX = 1; + static final int MAX_USERS_MAX = 200; + static final int MIN_WALL_OR_FLOOR_SIZE = -2; + static final int MAX_WALL_OR_FLOOR_SIZE = 1; + static final int MIN_CHAT_DISTANCE = 1; + static final int MAX_CHAT_DISTANCE = 99; + + private RoomSettingsInputGuard() { + } + + static boolean isValidRoomState(int value) { + return value >= 0 && value < RoomState.values().length; + } + + static RoomState roomState(int value) { + RoomState[] states = RoomState.values(); + return states[value]; + } + + static boolean isValidUsersMax(int value) { + return isInRange(value, MIN_USERS_MAX, MAX_USERS_MAX); + } + + static boolean isValidTagCount(int value) { + return isInRange(value, 0, MAX_TAGS); + } + + static boolean isValidTradeMode(int value) { + return isInRange(value, 0, 2); + } + + static boolean isValidModerationOption(int value) { + return isInRange(value, 0, 2); + } + + static boolean isValidWallOrFloorSize(int value) { + return isInRange(value, MIN_WALL_OR_FLOOR_SIZE, MAX_WALL_OR_FLOOR_SIZE); + } + + static boolean isValidChatMode(int value) { + return isInRange(value, 0, 2); + } + + static boolean isValidChatWeight(int value) { + return isInRange(value, 0, 2); + } + + static boolean isValidChatSpeed(int value) { + return isInRange(value, 0, 2); + } + + static boolean isValidChatDistance(int value) { + return isInRange(value, MIN_CHAT_DISTANCE, MAX_CHAT_DISTANCE); + } + + static boolean isValidChatProtection(int value) { + return isInRange(value, 0, 2); + } + + static boolean isSafePassword(String password) { + return password != null && password.length() <= MAX_PASSWORD_LENGTH; + } + + private static boolean isInRange(int value, int min, int max) { + return value >= min && value <= max; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/RoomSettingsSaveEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/RoomSettingsSaveEvent.java index 51fad249..d082746c 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/RoomSettingsSaveEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/RoomSettingsSaveEvent.java @@ -15,15 +15,6 @@ import java.util.Set; public class RoomSettingsSaveEvent extends MessageHandler { private static final Logger LOGGER = LoggerFactory.getLogger(RoomSettingsSaveEvent.class); - private static final int MAX_ROOM_PASSWORD_LENGTH = 64; - private static final int MAX_TAGS = 2; - private static final int MIN_USERS_MAX = 1; - private static final int MAX_USERS_MAX = 200; - private static final int MIN_THICKNESS = -2; - private static final int MAX_THICKNESS = 1; - private static final int MAX_OPTION_LEVEL = 2; - private static final int MIN_CHAT_DISTANCE = 1; - private static final int MAX_CHAT_DISTANCE = 99; @Override public void handle() throws Exception { @@ -57,13 +48,13 @@ public class RoomSettingsSaveEvent extends MessageHandler { } int stateId = this.packet.readInt(); - if (stateId < 0 || stateId >= RoomState.values().length) { + if (!RoomSettingsInputGuard.isValidRoomState(stateId)) { return; } - RoomState state = RoomState.values()[stateId]; + RoomState state = RoomSettingsInputGuard.roomState(stateId); String password = this.packet.readString(); - if (password.length() > MAX_ROOM_PASSWORD_LENGTH) { + if (!RoomSettingsInputGuard.isSafePassword(password)) { return; } if (state == RoomState.PASSWORD && password.isEmpty() && (room.getPassword() == null || room.getPassword().isEmpty())) { @@ -72,7 +63,7 @@ public class RoomSettingsSaveEvent extends MessageHandler { } int usersMax = this.packet.readInt(); - if (usersMax < MIN_USERS_MAX || usersMax > MAX_USERS_MAX) { + if (!RoomSettingsInputGuard.isValidUsersMax(usersMax)) { return; } @@ -80,7 +71,7 @@ public class RoomSettingsSaveEvent extends MessageHandler { StringBuilder tags = new StringBuilder(); Set uniqueTags = new HashSet<>(); int count = this.packet.readInt(); - if (count < 0 || count > MAX_TAGS) { + if (!RoomSettingsInputGuard.isValidTagCount(count)) { return; } for (int i = 0; i < count; i++) { @@ -152,17 +143,17 @@ public class RoomSettingsSaveEvent extends MessageHandler { int chatDistance = this.packet.readInt(); int chatProtection = this.packet.readInt(); - if (!isInRange(tradeMode, 0, MAX_OPTION_LEVEL) - || !isInRange(wallSize, MIN_THICKNESS, MAX_THICKNESS) - || !isInRange(floorSize, MIN_THICKNESS, MAX_THICKNESS) - || !isInRange(muteOption, 0, MAX_OPTION_LEVEL) - || !isInRange(kickOption, 0, MAX_OPTION_LEVEL) - || !isInRange(banOption, 0, MAX_OPTION_LEVEL) - || !isInRange(chatMode, 0, MAX_OPTION_LEVEL) - || !isInRange(chatWeight, 0, MAX_OPTION_LEVEL) - || !isInRange(chatSpeed, 0, MAX_OPTION_LEVEL) - || !isInRange(chatDistance, MIN_CHAT_DISTANCE, MAX_CHAT_DISTANCE) - || !isInRange(chatProtection, 0, MAX_OPTION_LEVEL)) { + if (!RoomSettingsInputGuard.isValidTradeMode(tradeMode) + || !RoomSettingsInputGuard.isValidWallOrFloorSize(wallSize) + || !RoomSettingsInputGuard.isValidWallOrFloorSize(floorSize) + || !RoomSettingsInputGuard.isValidModerationOption(muteOption) + || !RoomSettingsInputGuard.isValidModerationOption(kickOption) + || !RoomSettingsInputGuard.isValidModerationOption(banOption) + || !RoomSettingsInputGuard.isValidChatMode(chatMode) + || !RoomSettingsInputGuard.isValidChatWeight(chatWeight) + || !RoomSettingsInputGuard.isValidChatSpeed(chatSpeed) + || !RoomSettingsInputGuard.isValidChatDistance(chatDistance) + || !RoomSettingsInputGuard.isValidChatProtection(chatProtection)) { return; } @@ -198,7 +189,4 @@ public class RoomSettingsSaveEvent extends MessageHandler { } } - private static boolean isInRange(int value, int min, int max) { - return value >= min && value <= max; - } } diff --git a/Emulator/src/test/java/com/eu/habbo/messages/incoming/rooms/RoomSettingsInputGuardTest.java b/Emulator/src/test/java/com/eu/habbo/messages/incoming/rooms/RoomSettingsInputGuardTest.java new file mode 100644 index 00000000..db5e4c07 --- /dev/null +++ b/Emulator/src/test/java/com/eu/habbo/messages/incoming/rooms/RoomSettingsInputGuardTest.java @@ -0,0 +1,74 @@ +package com.eu.habbo.messages.incoming.rooms; + +import com.eu.habbo.habbohotel.rooms.RoomState; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class RoomSettingsInputGuardTest { + @Test + void validatesRoomStateBeforeIndexing() { + assertFalse(RoomSettingsInputGuard.isValidRoomState(-1)); + assertFalse(RoomSettingsInputGuard.isValidRoomState(RoomState.values().length)); + assertTrue(RoomSettingsInputGuard.isValidRoomState(RoomState.PASSWORD.getState())); + assertEquals(RoomState.PASSWORD, RoomSettingsInputGuard.roomState(RoomState.PASSWORD.getState())); + } + + @Test + void validatesRoomCapacityAndCosmeticSizes() { + assertFalse(RoomSettingsInputGuard.isValidUsersMax(-50)); + assertFalse(RoomSettingsInputGuard.isValidUsersMax(500)); + assertTrue(RoomSettingsInputGuard.isValidUsersMax(200)); + assertFalse(RoomSettingsInputGuard.isValidWallOrFloorSize(-50)); + assertFalse(RoomSettingsInputGuard.isValidWallOrFloorSize(50)); + assertTrue(RoomSettingsInputGuard.isValidWallOrFloorSize(-2)); + assertTrue(RoomSettingsInputGuard.isValidWallOrFloorSize(1)); + } + + @Test + void validatesRoomOptionEnums() { + assertFalse(RoomSettingsInputGuard.isValidTradeMode(-1)); + assertFalse(RoomSettingsInputGuard.isValidTradeMode(99)); + assertTrue(RoomSettingsInputGuard.isValidTradeMode(2)); + assertFalse(RoomSettingsInputGuard.isValidModerationOption(-1)); + assertFalse(RoomSettingsInputGuard.isValidModerationOption(99)); + assertTrue(RoomSettingsInputGuard.isValidModerationOption(2)); + assertFalse(RoomSettingsInputGuard.isValidChatMode(-1)); + assertFalse(RoomSettingsInputGuard.isValidChatMode(99)); + assertTrue(RoomSettingsInputGuard.isValidChatMode(2)); + assertFalse(RoomSettingsInputGuard.isValidChatWeight(-1)); + assertFalse(RoomSettingsInputGuard.isValidChatWeight(99)); + assertTrue(RoomSettingsInputGuard.isValidChatWeight(2)); + assertFalse(RoomSettingsInputGuard.isValidChatSpeed(-1)); + assertFalse(RoomSettingsInputGuard.isValidChatSpeed(99)); + assertTrue(RoomSettingsInputGuard.isValidChatSpeed(2)); + assertFalse(RoomSettingsInputGuard.isValidChatProtection(-1)); + assertFalse(RoomSettingsInputGuard.isValidChatProtection(99)); + assertTrue(RoomSettingsInputGuard.isValidChatProtection(2)); + } + + @Test + void validatesChatDistanceSafely() { + assertFalse(RoomSettingsInputGuard.isValidChatDistance(0)); + assertFalse(RoomSettingsInputGuard.isValidChatDistance(Integer.MIN_VALUE)); + assertFalse(RoomSettingsInputGuard.isValidChatDistance(500)); + assertTrue(RoomSettingsInputGuard.isValidChatDistance(1)); + assertTrue(RoomSettingsInputGuard.isValidChatDistance(99)); + } + + @Test + void validatesTagCount() { + assertFalse(RoomSettingsInputGuard.isValidTagCount(-1)); + assertFalse(RoomSettingsInputGuard.isValidTagCount(3)); + assertTrue(RoomSettingsInputGuard.isValidTagCount(0)); + assertTrue(RoomSettingsInputGuard.isValidTagCount(2)); + } + + @Test + void rejectsOversizedPasswords() { + assertTrue(RoomSettingsInputGuard.isSafePassword("short-secret")); + assertFalse(RoomSettingsInputGuard.isSafePassword("x".repeat(RoomSettingsInputGuard.MAX_PASSWORD_LENGTH + 1))); + } +}