Merge pull request #270 from simoleo89/fix/pets-package-name-inputs

fix(pets): bound package names
This commit is contained in:
DuckieTM
2026-06-18 12:55:27 +02:00
committed by GitHub
2 changed files with 87 additions and 6 deletions
@@ -5,12 +5,15 @@ import com.eu.habbo.habbohotel.pets.Pet;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomTile;
import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.messages.incoming.catalog.CheckPetNameEvent;
import com.eu.habbo.messages.incoming.MessageHandler;
import com.eu.habbo.messages.incoming.rooms.items.RoomItemInputGuard;
import com.eu.habbo.messages.outgoing.catalog.AlertPurchaseFailedComposer;
import com.eu.habbo.messages.outgoing.rooms.UpdateStackHeightComposer;
import com.eu.habbo.messages.outgoing.rooms.items.RemoveFloorItemComposer;
import com.eu.habbo.messages.outgoing.rooms.pets.PetPackageNameValidationComposer;
import com.eu.habbo.threading.runnables.QueryDeleteHabboItem;
import org.apache.commons.lang3.StringUtils;
public class PetPackageNameEvent extends MessageHandler {
@Override
@@ -18,13 +21,24 @@ public class PetPackageNameEvent extends MessageHandler {
int itemId = this.packet.readInt();
String name = this.packet.readString();
if (!RoomItemInputGuard.isPositiveId(itemId)) {
return;
}
Room room = this.client.getHabbo().getHabboInfo().getCurrentRoom();
if (room != null) {
HabboItem item = room.getHabboItem(itemId);
if (item != null) {
if (item.getUserId() == this.client.getHabbo().getHabboInfo().getId()) {
if (name.matches("^[a-zA-Z0-9]*$")) {
int nameError = validatePetPackageName(name);
if (nameError == PetPackageNameValidationComposer.CLOSE_WIDGET) {
RoomTile tile = room.getLayout().getTile(item.getX(), item.getY());
if (tile == null) {
this.client.sendResponse(new AlertPurchaseFailedComposer(AlertPurchaseFailedComposer.SERVER_ERROR));
return;
}
Pet pet = null;
if (item.getBaseItem().getName().equalsIgnoreCase("val11_present")) {
@@ -55,20 +69,19 @@ public class PetPackageNameEvent extends MessageHandler {
room.placePet(pet, item.getX(), item.getY(), item.getZ(), item.getRotation());
pet.setUserId(this.client.getHabbo().getHabboInfo().getId());
pet.needsUpdate = true;
pet.getRoomUnit().setLocation(room.getLayout().getTile(item.getX(), item.getY()));
pet.getRoomUnit().setLocation(tile);
pet.getRoomUnit().setZ(item.getZ());
Emulator.getThreading().run(new QueryDeleteHabboItem(item.getId()));
room.removeHabboItem(item);
room.sendComposer(new RemoveFloorItemComposer(item).compose());
RoomTile tile = room.getLayout().getTile(item.getX(), item.getY());
room.updateTile(room.getLayout().getTile(item.getX(), item.getY()));
room.updateTile(tile);
room.sendComposer(new UpdateStackHeightComposer(tile.x, tile.y, tile.z, tile.relativeHeight()).compose());
item.setUserId(0);
} else {
this.client.sendResponse(new AlertPurchaseFailedComposer(AlertPurchaseFailedComposer.SERVER_ERROR));
}
} else {
this.client.sendResponse(new PetPackageNameValidationComposer(itemId, PetPackageNameValidationComposer.CONTAINS_INVALID_CHARS, name.replaceAll("^[a-zA-Z0-9]*$", "")));
this.client.sendResponse(new PetPackageNameValidationComposer(itemId, nameError, name == null ? "" : name));
return;
}
}
@@ -78,4 +91,20 @@ public class PetPackageNameEvent extends MessageHandler {
this.client.sendResponse(new PetPackageNameValidationComposer(itemId, PetPackageNameValidationComposer.CLOSE_WIDGET, ""));
}
}
static int validatePetPackageName(String name) {
if (name == null || name.length() < CheckPetNameEvent.PET_NAME_LENGTH_MINIMUM) {
return PetPackageNameValidationComposer.NAME_TOO_SHORT;
}
if (name.length() > CheckPetNameEvent.PET_NAME_LENGTH_MAXIMUM) {
return PetPackageNameValidationComposer.NAME_TOO_LONG;
}
if (!StringUtils.isAlphanumeric(name)) {
return PetPackageNameValidationComposer.CONTAINS_INVALID_CHARS;
}
return PetPackageNameValidationComposer.CLOSE_WIDGET;
}
}
@@ -0,0 +1,52 @@
package com.eu.habbo.messages.incoming.rooms.pets;
import org.junit.jupiter.api.Test;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.assertTrue;
class PetPackageNameContractTest {
private static String source() throws Exception {
return Files.readString(Path.of("src/main/java/com/eu/habbo/messages/incoming/rooms/pets/PetPackageNameEvent.java"));
}
@Test
void validatesItemIdBeforeRoomItemLookup() throws Exception {
String source = source();
int itemIdRead = source.indexOf("int itemId = this.packet.readInt()");
int idGuard = source.indexOf("RoomItemInputGuard.isPositiveId(itemId)", itemIdRead);
int lookup = source.indexOf("HabboItem item = room.getHabboItem(itemId)", idGuard);
assertTrue(itemIdRead > -1, "pet package handler should read an item id");
assertTrue(idGuard > itemIdRead, "pet package handler should reject invalid item ids");
assertTrue(lookup > idGuard, "item id validation must happen before room item lookup");
}
@Test
void validatesNameAndTileBeforeCreatingPet() throws Exception {
String source = source();
int nameValidation = source.indexOf("int nameError = validatePetPackageName(name)");
int tileLookup = source.indexOf("RoomTile tile = room.getLayout().getTile", nameValidation);
int createPet = source.indexOf("createPet", tileLookup);
assertTrue(nameValidation > -1, "pet package handler should validate package pet names");
assertTrue(tileLookup > nameValidation, "tile lookup should happen after name validation");
assertTrue(createPet > tileLookup, "pet creation must happen after validating the target tile");
}
@Test
void packageNamesUseNormalPetNamePolicy() throws Exception {
String source = source();
assertTrue(source.contains("CheckPetNameEvent.PET_NAME_LENGTH_MINIMUM"),
"package pet names should use the configured minimum pet-name length");
assertTrue(source.contains("CheckPetNameEvent.PET_NAME_LENGTH_MAXIMUM"),
"package pet names should use the configured maximum pet-name length");
assertTrue(source.contains("StringUtils.isAlphanumeric(name)"),
"package pet names should use alphanumeric validation");
}
}