fix(items): require seed ownership for monsterplants

Reject monsterplant seed redemption when the caller does not own the placed seed. Without this guard, a user in the same room could trigger ToggleFloorItemEvent against another user's seed and have the server delete that item while creating the monsterplant pet for the attacker.

Add a contract test covering the ownership guard before createMonsterplant is reached.
This commit is contained in:
simoleo89
2026-06-13 17:28:09 +02:00
parent 87e1ef94f7
commit 60ccc8c80b
2 changed files with 33 additions and 0 deletions
@@ -103,6 +103,10 @@ public class ToggleFloorItemEvent extends MessageHandler {
// Do not move to onClick(). Wired could trigger it.
if (item instanceof InteractionMonsterPlantSeed) {
if (item.getUserId() != this.client.getHabbo().getHabboInfo().getId()) {
return;
}
Emulator.getThreading().run(new QueryDeleteHabboItem(item.getId()));
boolean isRare = item.getBaseItem().getName().contains("rare");
@@ -0,0 +1,29 @@
package com.eu.habbo.messages.incoming.rooms.items;
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 MonsterPlantSeedOwnershipContractTest {
@Test
void monsterPlantSeedsCanOnlyBeRedeemedByTheirOwner() throws Exception {
String source = Files.readString(Path.of("src/main/java/com/eu/habbo/messages/incoming/rooms/items/ToggleFloorItemEvent.java"));
int seedBranch = source.indexOf("item instanceof InteractionMonsterPlantSeed");
assertTrue(seedBranch >= 0, "ToggleFloorItemEvent must keep monsterplant seed handling explicit");
String seedHandling = source.substring(seedBranch, Math.min(source.length(), seedBranch + 1400));
String ownershipGuard = "if (item.getUserId() != this.client.getHabbo().getHabboInfo().getId())";
assertTrue(seedHandling.contains(ownershipGuard),
"Monsterplant seed redemption must reject callers who do not own the seed");
assertTrue(seedHandling.contains("createMonsterplant"),
"Monsterplant seed handling must create the pet inside the guarded branch");
assertTrue(seedHandling.indexOf(ownershipGuard) < seedHandling.indexOf("createMonsterplant"),
"Ownership rejection must happen before creating the pet");
}
}