From 3304edafb7105161aab3cf81d456b211d5125c18 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Wed, 17 Jun 2026 18:54:27 +0200 Subject: [PATCH] fix(wired): bound user condition inputs --- .../WiredConditionHabboHasEffect.java | 30 ++++++++--- .../WiredConditionHabboHasHandItem.java | 51 +++++++++++-------- .../WiredConditionHabboWearsBadge.java | 26 +++++++--- .../WiredUserConditionInputGuard.java | 45 ++++++++++++++++ .../WiredUserConditionInputGuardTest.java | 33 ++++++++++++ 5 files changed, 151 insertions(+), 34 deletions(-) create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredUserConditionInputGuard.java create mode 100644 Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredUserConditionInputGuardTest.java diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboHasEffect.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboHasEffect.java index 2075513d..e49ceddf 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboHasEffect.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboHasEffect.java @@ -87,14 +87,32 @@ public class WiredConditionHabboHasEffect extends InteractionWiredCondition { @Override public void loadWiredData(ResultSet set, Room room) throws SQLException { String wiredData = set.getString("wired_data"); + if (wiredData == null || wiredData.isEmpty()) { + this.onPickUp(); + return; + } if (wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.effectId = data.effectId; - this.userSource = data.userSource; + JsonData data; + try { + data = WiredManager.getGson().fromJson(wiredData, JsonData.class); + } catch (RuntimeException ignored) { + this.onPickUp(); + return; + } + if (data == null) { + this.onPickUp(); + return; + } + this.effectId = WiredUserConditionInputGuard.normalizeEffectId(data.effectId); + this.userSource = WiredUserConditionInputGuard.normalizeUserSource(data.userSource); this.quantifier = this.normalizeQuantifier(data.quantifier, QUANTIFIER_ANY); } else { - this.effectId = Integer.parseInt(wiredData); + try { + this.effectId = WiredUserConditionInputGuard.normalizeEffectId(Integer.parseInt(wiredData)); + } catch (NumberFormatException ignored) { + this.effectId = 0; + } this.userSource = WiredSourceUtil.SOURCE_TRIGGER; this.quantifier = QUANTIFIER_ANY; } @@ -134,8 +152,8 @@ public class WiredConditionHabboHasEffect extends InteractionWiredCondition { public boolean saveData(WiredSettings settings) { if(settings.getIntParams().length < 1) return false; int[] params = settings.getIntParams(); - this.effectId = params[0]; - this.userSource = (params.length > 1) ? params[1] : WiredSourceUtil.SOURCE_TRIGGER; + this.effectId = WiredUserConditionInputGuard.normalizeEffectId(params[0]); + this.userSource = (params.length > 1) ? WiredUserConditionInputGuard.normalizeUserSource(params[1]) : WiredSourceUtil.SOURCE_TRIGGER; this.quantifier = (params.length > 2) ? this.normalizeQuantifier(params[2], QUANTIFIER_ANY) : QUANTIFIER_ANY; return true; diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboHasHandItem.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboHasHandItem.java index d949e4bd..c535e271 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboHasHandItem.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboHasHandItem.java @@ -10,15 +10,12 @@ import com.eu.habbo.habbohotel.wired.core.WiredManager; import com.eu.habbo.habbohotel.wired.core.WiredContext; import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil; import com.eu.habbo.messages.ServerMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; public class WiredConditionHabboHasHandItem extends InteractionWiredCondition { - private static final Logger LOGGER = LoggerFactory.getLogger(WiredConditionHabboHasHandItem.class); protected static final int QUANTIFIER_ALL = 0; protected static final int QUANTIFIER_ANY = 1; @@ -62,9 +59,9 @@ public class WiredConditionHabboHasHandItem extends InteractionWiredCondition { @Override public boolean saveData(WiredSettings settings) { if(settings.getIntParams().length < 1) return false; - this.handItem = this.normalizeHandItem(settings.getIntParams()[0]); + this.handItem = WiredUserConditionInputGuard.normalizeHandItemId(settings.getIntParams()[0]); int[] params = settings.getIntParams(); - this.userSource = (params.length > 1) ? params[1] : WiredSourceUtil.SOURCE_TRIGGER; + this.userSource = (params.length > 1) ? WiredUserConditionInputGuard.normalizeUserSource(params[1]) : WiredSourceUtil.SOURCE_TRIGGER; this.quantifier = (params.length > 2) ? this.normalizeQuantifier(params[2]) : QUANTIFIER_ALL; return true; @@ -99,21 +96,35 @@ public class WiredConditionHabboHasHandItem extends InteractionWiredCondition { @Override public void loadWiredData(ResultSet set, Room room) throws SQLException { - try { - String wiredData = set.getString("wired_data"); + String wiredData = set.getString("wired_data"); + if (wiredData == null || wiredData.isEmpty()) { + this.onPickUp(); + return; + } - if (wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.handItem = this.normalizeHandItem(data.handItemId); - this.userSource = data.userSource; - this.quantifier = this.normalizeQuantifier(data.quantifier); - } else { - this.handItem = this.normalizeHandItem(Integer.parseInt(wiredData)); - this.userSource = WiredSourceUtil.SOURCE_TRIGGER; - this.quantifier = QUANTIFIER_ALL; + if (wiredData.startsWith("{")) { + JsonData data; + try { + data = WiredManager.getGson().fromJson(wiredData, JsonData.class); + } catch (RuntimeException ignored) { + this.onPickUp(); + return; } - } catch (Exception e) { - LOGGER.error("Caught exception", e); + if (data == null) { + this.onPickUp(); + return; + } + this.handItem = WiredUserConditionInputGuard.normalizeHandItemId(data.handItemId); + this.userSource = WiredUserConditionInputGuard.normalizeUserSource(data.userSource); + this.quantifier = this.normalizeQuantifier(data.quantifier); + } else { + try { + this.handItem = WiredUserConditionInputGuard.normalizeHandItemId(Integer.parseInt(wiredData)); + } catch (NumberFormatException ignored) { + this.handItem = 0; + } + this.userSource = WiredSourceUtil.SOURCE_TRIGGER; + this.quantifier = QUANTIFIER_ALL; } } @@ -156,10 +167,6 @@ public class WiredConditionHabboHasHandItem extends InteractionWiredCondition { return true; } - protected int normalizeHandItem(int value) { - return Math.max(0, value); - } - protected int normalizeQuantifier(int value) { return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL; } diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboWearsBadge.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboWearsBadge.java index 83c85a8f..6d01aeaf 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboWearsBadge.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboWearsBadge.java @@ -103,14 +103,28 @@ public class WiredConditionHabboWearsBadge extends InteractionWiredCondition { @Override public void loadWiredData(ResultSet set, Room room) throws SQLException { String wiredData = set.getString("wired_data"); + if (wiredData == null) { + this.onPickUp(); + return; + } if (wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.badge = data.badge; - this.userSource = data.userSource; + JsonData data; + try { + data = WiredManager.getGson().fromJson(wiredData, JsonData.class); + } catch (RuntimeException ignored) { + this.onPickUp(); + return; + } + if (data == null) { + this.onPickUp(); + return; + } + this.badge = WiredUserConditionInputGuard.normalizeBadgeCode(data.badge); + this.userSource = WiredUserConditionInputGuard.normalizeUserSource(data.userSource); this.quantifier = this.normalizeQuantifier(data.quantifier, QUANTIFIER_ANY); } else { - this.badge = wiredData; + this.badge = WiredUserConditionInputGuard.normalizeBadgeCode(wiredData); this.userSource = WiredSourceUtil.SOURCE_TRIGGER; this.quantifier = QUANTIFIER_ANY; } @@ -147,9 +161,9 @@ public class WiredConditionHabboWearsBadge extends InteractionWiredCondition { @Override public boolean saveData(WiredSettings settings) { - this.badge = settings.getStringParam(); + this.badge = WiredUserConditionInputGuard.normalizeBadgeCode(settings.getStringParam()); int[] params = settings.getIntParams(); - this.userSource = (params.length > 0) ? params[0] : WiredSourceUtil.SOURCE_TRIGGER; + this.userSource = (params.length > 0) ? WiredUserConditionInputGuard.normalizeUserSource(params[0]) : WiredSourceUtil.SOURCE_TRIGGER; this.quantifier = (params.length > 1) ? this.normalizeQuantifier(params[1], QUANTIFIER_ANY) : QUANTIFIER_ANY; return true; diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredUserConditionInputGuard.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredUserConditionInputGuard.java new file mode 100644 index 00000000..86646983 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredUserConditionInputGuard.java @@ -0,0 +1,45 @@ +package com.eu.habbo.habbohotel.items.interactions.wired.conditions; + +import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil; + +public final class WiredUserConditionInputGuard { + public static final int MAX_BADGE_CODE_LENGTH = 64; + public static final int MAX_EFFECT_ID = 10_000; + public static final int MAX_HAND_ITEM_ID = 10_000; + + private WiredUserConditionInputGuard() { + } + + public static String normalizeBadgeCode(String value) { + if (value == null) { + return ""; + } + + String normalized = value.trim().replace('\t', ' ').replace('\r', ' ').replace('\n', ' '); + if (normalized.length() > MAX_BADGE_CODE_LENGTH) { + return normalized.substring(0, MAX_BADGE_CODE_LENGTH); + } + + return normalized; + } + + public static int normalizeUserSource(int value) { + return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER; + } + + public static int normalizeEffectId(int value) { + if (value < 0) { + return 0; + } + + return Math.min(value, MAX_EFFECT_ID); + } + + public static int normalizeHandItemId(int value) { + if (value < 0) { + return 0; + } + + return Math.min(value, MAX_HAND_ITEM_ID); + } +} diff --git a/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredUserConditionInputGuardTest.java b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredUserConditionInputGuardTest.java new file mode 100644 index 00000000..a1251715 --- /dev/null +++ b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredUserConditionInputGuardTest.java @@ -0,0 +1,33 @@ +package com.eu.habbo.habbohotel.items.interactions.wired.conditions; + +import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +class WiredUserConditionInputGuardTest { + + @Test + void badgeCodesAreBoundedAndSingleLine() { + assertEquals("", WiredUserConditionInputGuard.normalizeBadgeCode(null)); + assertEquals("ACH Test", WiredUserConditionInputGuard.normalizeBadgeCode(" ACH\tTest\n")); + String normalized = WiredUserConditionInputGuard.normalizeBadgeCode("x".repeat(WiredUserConditionInputGuard.MAX_BADGE_CODE_LENGTH + 10)); + assertEquals(WiredUserConditionInputGuard.MAX_BADGE_CODE_LENGTH, normalized.length()); + assertFalse(normalized.contains("\n")); + } + + @Test + void numericIdsAreNonNegativeAndCapped() { + assertEquals(0, WiredUserConditionInputGuard.normalizeEffectId(-1)); + assertEquals(WiredUserConditionInputGuard.MAX_EFFECT_ID, WiredUserConditionInputGuard.normalizeEffectId(Integer.MAX_VALUE)); + assertEquals(0, WiredUserConditionInputGuard.normalizeHandItemId(-1)); + assertEquals(WiredUserConditionInputGuard.MAX_HAND_ITEM_ID, WiredUserConditionInputGuard.normalizeHandItemId(Integer.MAX_VALUE)); + } + + @Test + void unknownUserSourcesFallBackToTrigger() { + assertEquals(WiredSourceUtil.SOURCE_TRIGGER, WiredUserConditionInputGuard.normalizeUserSource(-1)); + assertEquals(WiredSourceUtil.SOURCE_SELECTOR, WiredUserConditionInputGuard.normalizeUserSource(WiredSourceUtil.SOURCE_SELECTOR)); + } +}