From 25e38fbbeb8f67ce4e641f902cce2faf9af75480 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Wed, 17 Jun 2026 19:21:54 +0200 Subject: [PATCH] fix(wired): bound avatar condition payloads --- .../WiredConditionHabboHasEffect.java | 44 +++++++++++++---- .../WiredConditionHabboHasHandItem.java | 28 +++++++---- .../WiredConditionHabboWearsBadge.java | 45 +++++++++++++++--- .../WiredConditionAvatarPayloadGuardTest.java | 47 +++++++++++++++++++ 4 files changed, 141 insertions(+), 23 deletions(-) create mode 100644 Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionAvatarPayloadGuardTest.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..82ca6e6d 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 @@ -18,6 +18,7 @@ import java.util.List; public class WiredConditionHabboHasEffect extends InteractionWiredCondition { protected static final int QUANTIFIER_ALL = 0; protected static final int QUANTIFIER_ANY = 1; + protected static final int MAX_EFFECT_ID = 10_000; public static final WiredConditionType type = WiredConditionType.ACTOR_WEARS_EFFECT; @@ -86,17 +87,36 @@ public class WiredConditionHabboHasEffect extends InteractionWiredCondition { @Override public void loadWiredData(ResultSet set, Room room) throws SQLException { + this.onPickUp(); String wiredData = set.getString("wired_data"); + if (wiredData == null || wiredData.isEmpty()) { + 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 exception) { + this.onPickUp(); + return; + } + + if (data == null) { + return; + } + + this.effectId = this.normalizeEffectId(data.effectId); + this.userSource = this.normalizeUserSource(data.userSource); this.quantifier = this.normalizeQuantifier(data.quantifier, QUANTIFIER_ANY); } else { - this.effectId = Integer.parseInt(wiredData); - this.userSource = WiredSourceUtil.SOURCE_TRIGGER; - this.quantifier = QUANTIFIER_ANY; + try { + this.effectId = this.normalizeEffectId(Integer.parseInt(wiredData)); + this.userSource = WiredSourceUtil.SOURCE_TRIGGER; + this.quantifier = QUANTIFIER_ANY; + } catch (NumberFormatException exception) { + this.onPickUp(); + } } } @@ -134,8 +154,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 = this.normalizeEffectId(params[0]); + this.userSource = (params.length > 1) ? this.normalizeUserSource(params[1]) : WiredSourceUtil.SOURCE_TRIGGER; this.quantifier = (params.length > 2) ? this.normalizeQuantifier(params[2], QUANTIFIER_ANY) : QUANTIFIER_ANY; return true; @@ -153,6 +173,14 @@ public class WiredConditionHabboHasEffect extends InteractionWiredCondition { return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL; } + protected int normalizeEffectId(int value) { + return Math.max(0, Math.min(MAX_EFFECT_ID, value)); + } + + protected int normalizeUserSource(int value) { + return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER; + } + static class JsonData { int effectId; int userSource; 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..da4ccb23 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,17 +10,15 @@ 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; + protected static final int MAX_HAND_ITEM_ID = 10_000; public static final WiredConditionType type = WiredConditionType.ACTOR_HAS_HANDITEM; @@ -64,7 +62,7 @@ public class WiredConditionHabboHasHandItem extends InteractionWiredCondition { if(settings.getIntParams().length < 1) return false; this.handItem = this.normalizeHandItem(settings.getIntParams()[0]); int[] params = settings.getIntParams(); - this.userSource = (params.length > 1) ? params[1] : WiredSourceUtil.SOURCE_TRIGGER; + this.userSource = (params.length > 1) ? this.normalizeUserSource(params[1]) : WiredSourceUtil.SOURCE_TRIGGER; this.quantifier = (params.length > 2) ? this.normalizeQuantifier(params[2]) : QUANTIFIER_ALL; return true; @@ -99,13 +97,21 @@ public class WiredConditionHabboHasHandItem extends InteractionWiredCondition { @Override public void loadWiredData(ResultSet set, Room room) throws SQLException { - try { - String wiredData = set.getString("wired_data"); + this.onPickUp(); + String wiredData = set.getString("wired_data"); + if (wiredData == null || wiredData.isEmpty()) { + return; + } + try { if (wiredData.startsWith("{")) { JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); + if (data == null) { + return; + } + this.handItem = this.normalizeHandItem(data.handItemId); - this.userSource = data.userSource; + this.userSource = this.normalizeUserSource(data.userSource); this.quantifier = this.normalizeQuantifier(data.quantifier); } else { this.handItem = this.normalizeHandItem(Integer.parseInt(wiredData)); @@ -113,7 +119,7 @@ public class WiredConditionHabboHasHandItem extends InteractionWiredCondition { this.quantifier = QUANTIFIER_ALL; } } catch (Exception e) { - LOGGER.error("Caught exception", e); + this.onPickUp(); } } @@ -157,13 +163,17 @@ public class WiredConditionHabboHasHandItem extends InteractionWiredCondition { } protected int normalizeHandItem(int value) { - return Math.max(0, value); + return Math.max(0, Math.min(MAX_HAND_ITEM_ID, value)); } protected int normalizeQuantifier(int value) { return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL; } + protected int normalizeUserSource(int value) { + return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER; + } + static class JsonData { int handItemId; int userSource; 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..28c173b8 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 @@ -20,6 +20,7 @@ import java.util.List; public class WiredConditionHabboWearsBadge extends InteractionWiredCondition { protected static final int QUANTIFIER_ALL = 0; protected static final int QUANTIFIER_ANY = 1; + protected static final int MAX_BADGE_CODE_LENGTH = 64; public static final WiredConditionType type = WiredConditionType.ACTOR_WEARS_BADGE; @@ -37,6 +38,10 @@ public class WiredConditionHabboWearsBadge extends InteractionWiredCondition { @Override public boolean evaluate(WiredContext ctx) { + if (ctx == null || ctx.room() == null) { + return false; + } + Room room = ctx.room(); List targets = WiredSourceUtil.resolveUsers(ctx, this.userSource); if (targets.isEmpty()) return false; @@ -102,15 +107,30 @@ public class WiredConditionHabboWearsBadge extends InteractionWiredCondition { @Override public void loadWiredData(ResultSet set, Room room) throws SQLException { + this.onPickUp(); String wiredData = set.getString("wired_data"); + if (wiredData == null || wiredData.isEmpty()) { + 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 exception) { + this.onPickUp(); + return; + } + + if (data == null) { + return; + } + + this.badge = this.normalizeBadge(data.badge); + this.userSource = this.normalizeUserSource(data.userSource); this.quantifier = this.normalizeQuantifier(data.quantifier, QUANTIFIER_ANY); } else { - this.badge = wiredData; + this.badge = this.normalizeBadge(wiredData); this.userSource = WiredSourceUtil.SOURCE_TRIGGER; this.quantifier = QUANTIFIER_ANY; } @@ -147,9 +167,9 @@ public class WiredConditionHabboWearsBadge extends InteractionWiredCondition { @Override public boolean saveData(WiredSettings settings) { - this.badge = settings.getStringParam(); + this.badge = this.normalizeBadge(settings.getStringParam()); int[] params = settings.getIntParams(); - this.userSource = (params.length > 0) ? params[0] : WiredSourceUtil.SOURCE_TRIGGER; + this.userSource = (params.length > 0) ? this.normalizeUserSource(params[0]) : WiredSourceUtil.SOURCE_TRIGGER; this.quantifier = (params.length > 1) ? this.normalizeQuantifier(params[1], QUANTIFIER_ANY) : QUANTIFIER_ANY; return true; @@ -167,6 +187,19 @@ public class WiredConditionHabboWearsBadge extends InteractionWiredCondition { return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL; } + protected String normalizeBadge(String value) { + if (value == null) { + return ""; + } + + String normalized = value.trim(); + return normalized.length() <= MAX_BADGE_CODE_LENGTH ? normalized : normalized.substring(0, MAX_BADGE_CODE_LENGTH); + } + + protected int normalizeUserSource(int value) { + return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER; + } + static class JsonData { String badge; int userSource; diff --git a/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionAvatarPayloadGuardTest.java b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionAvatarPayloadGuardTest.java new file mode 100644 index 00000000..58f0050d --- /dev/null +++ b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionAvatarPayloadGuardTest.java @@ -0,0 +1,47 @@ +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; + +class WiredConditionAvatarPayloadGuardTest { + @Test + void effectIdsSourcesAndQuantifiersAreBounded() { + WiredConditionHabboHasEffect condition = new WiredConditionHabboHasEffect(1, 1, null, "", 0, 0); + + assertEquals(0, condition.normalizeEffectId(-1)); + assertEquals(23, condition.normalizeEffectId(23)); + assertEquals(WiredConditionHabboHasEffect.MAX_EFFECT_ID, condition.normalizeEffectId(Integer.MAX_VALUE)); + assertEquals(WiredSourceUtil.SOURCE_CLICKED_USER, condition.normalizeUserSource(WiredSourceUtil.SOURCE_CLICKED_USER)); + assertEquals(WiredSourceUtil.SOURCE_TRIGGER, condition.normalizeUserSource(777)); + assertEquals(1, condition.normalizeQuantifier(1, 0)); + assertEquals(0, condition.normalizeQuantifier(5, 0)); + } + + @Test + void handItemIdsSourcesAndQuantifiersAreBounded() { + WiredConditionHabboHasHandItem condition = new WiredConditionHabboHasHandItem(1, 1, null, "", 0, 0); + + assertEquals(0, condition.normalizeHandItem(-1)); + assertEquals(9, condition.normalizeHandItem(9)); + assertEquals(WiredConditionHabboHasHandItem.MAX_HAND_ITEM_ID, condition.normalizeHandItem(Integer.MAX_VALUE)); + assertEquals(WiredSourceUtil.SOURCE_SIGNAL, condition.normalizeUserSource(WiredSourceUtil.SOURCE_SIGNAL)); + assertEquals(WiredSourceUtil.SOURCE_TRIGGER, condition.normalizeUserSource(-44)); + assertEquals(1, condition.normalizeQuantifier(1)); + assertEquals(0, condition.normalizeQuantifier(8)); + } + + @Test + void badgeCodesSourcesAndQuantifiersAreBounded() { + WiredConditionHabboWearsBadge condition = new WiredConditionHabboWearsBadge(1, 1, null, "", 0, 0); + + assertEquals("", condition.normalizeBadge(null)); + assertEquals("ADM", condition.normalizeBadge(" ADM ")); + assertEquals(WiredConditionHabboWearsBadge.MAX_BADGE_CODE_LENGTH, condition.normalizeBadge("x".repeat(200)).length()); + assertEquals(WiredSourceUtil.SOURCE_SELECTOR, condition.normalizeUserSource(WiredSourceUtil.SOURCE_SELECTOR)); + assertEquals(WiredSourceUtil.SOURCE_TRIGGER, condition.normalizeUserSource(66)); + assertEquals(1, condition.normalizeQuantifier(1, 0)); + assertEquals(0, condition.normalizeQuantifier(3, 0)); + } +}