From 60b998f90905bfee2dd28b8d4259308565f0a9e5 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Wed, 17 Jun 2026 20:18:48 +0200 Subject: [PATCH] fix(wired): bound bot effect payloads --- .../wired/effects/WiredEffectBotClothes.java | 20 +++--- .../effects/WiredEffectBotFollowHabbo.java | 24 +++---- .../effects/WiredEffectBotGiveHandItem.java | 24 +++---- .../wired/effects/WiredEffectBotTalk.java | 24 +++---- .../effects/WiredEffectBotTalkToHabbo.java | 24 +++---- .../wired/effects/WiredEffectBotTeleport.java | 33 ++++----- .../effects/WiredEffectBotWalkToFurni.java | 33 ++++----- .../effects/WiredEffectPayloadGuard.java | 67 +++++++++++++++++++ .../effects/WiredEffectPayloadGuardTest.java | 35 ++++++++++ 9 files changed, 196 insertions(+), 88 deletions(-) create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectPayloadGuard.java create mode 100644 Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectPayloadGuardTest.java diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotClothes.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotClothes.java index 345fbb0c..998d533b 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotClothes.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotClothes.java @@ -106,21 +106,21 @@ public class WiredEffectBotClothes extends InteractionWiredEffect { public void loadWiredData(ResultSet set, Room room) throws SQLException { String wiredData = set.getString("wired_data"); - if(wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.setDelay(data.delay); - this.botName = data.bot_name; - this.botLook = data.look; - this.botSource = (data.botSource != null) - ? WiredBotSourceUtil.normalizeBotSource(data.botSource) + JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class); + if(jsonData != null) { + this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay)); + this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name); + this.botLook = jsonData.look != null ? jsonData.look : ""; + this.botSource = (jsonData.botSource != null) + ? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource) : WiredBotSourceUtil.SOURCE_BOT_NAME; } else { - String[] data = wiredData.split(((char) 9) + ""); + String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0]; if (data.length >= 3) { - this.setDelay(Integer.parseInt(data[0])); - this.botName = data[1]; + this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0])); + this.botName = WiredEffectPayloadGuard.text(data[1]); this.botLook = data[2]; } diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotFollowHabbo.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotFollowHabbo.java index a1a80fe7..0d7bfb5f 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotFollowHabbo.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotFollowHabbo.java @@ -143,23 +143,23 @@ public class WiredEffectBotFollowHabbo extends InteractionWiredEffect { public void loadWiredData(ResultSet set, Room room) throws SQLException { String wiredData = set.getString("wired_data"); - if(wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.setDelay(data.delay); - this.mode = data.mode; - this.botName = data.bot_name; - this.userSource = data.userSource; - this.botSource = (data.botSource != null) - ? WiredBotSourceUtil.normalizeBotSource(data.botSource) + JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class); + if(jsonData != null) { + this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay)); + this.mode = WiredEffectPayloadGuard.mode(jsonData.mode); + this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name); + this.userSource = WiredSourceUtil.isDefaultUserSource(jsonData.userSource) ? jsonData.userSource : WiredSourceUtil.SOURCE_TRIGGER; + this.botSource = (jsonData.botSource != null) + ? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource) : WiredBotSourceUtil.SOURCE_BOT_NAME; } else { - String[] data = wiredData.split(((char) 9) + ""); + String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0]; if (data.length == 3) { - this.setDelay(Integer.parseInt(data[0])); - this.mode = (data[1].equalsIgnoreCase("1") ? 1 : 0); - this.botName = data[2]; + this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0])); + this.mode = WiredEffectPayloadGuard.mode(WiredEffectPayloadGuard.parseInt(data[1], 0)); + this.botName = WiredEffectPayloadGuard.text(data[2]); } this.needsUpdate(true); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotGiveHandItem.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotGiveHandItem.java index 53a8be66..97e7505b 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotGiveHandItem.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotGiveHandItem.java @@ -153,23 +153,23 @@ public class WiredEffectBotGiveHandItem extends InteractionWiredEffect { public void loadWiredData(ResultSet set, Room room) throws SQLException { String wiredData = set.getString("wired_data"); - if(wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.setDelay(data.delay); - this.itemId = this.normalizeHandItem(data.item_id); - this.botName = data.bot_name; - this.userSource = this.normalizeUserSource(data.userSource); - this.botSource = ((data.botSource == WiredSourceUtil.SOURCE_TRIGGER) && this.botName != null && !this.botName.isEmpty()) + JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class); + if(jsonData != null) { + this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay)); + this.itemId = this.normalizeHandItem(jsonData.item_id); + this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name); + this.userSource = this.normalizeUserSource(jsonData.userSource); + this.botSource = ((jsonData.botSource == WiredSourceUtil.SOURCE_TRIGGER) && this.botName != null && !this.botName.isEmpty()) ? BOT_SOURCE_NAME - : this.normalizeBotSource(data.botSource); + : this.normalizeBotSource(jsonData.botSource); } else { - String[] data = wiredData.split(((char) 9) + ""); + String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0]; if (data.length == 3) { - this.setDelay(Integer.parseInt(data[0])); - this.itemId = this.normalizeHandItem(Integer.parseInt(data[1])); - this.botName = data[2]; + this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0])); + this.itemId = this.normalizeHandItem(WiredEffectPayloadGuard.parseInt(data[1], 0)); + this.botName = WiredEffectPayloadGuard.text(data[2]); } this.needsUpdate(true); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotTalk.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotTalk.java index b4f20a8f..fb392171 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotTalk.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotTalk.java @@ -144,23 +144,23 @@ public class WiredEffectBotTalk extends InteractionWiredEffect { public void loadWiredData(ResultSet set, Room room) throws SQLException { String wiredData = set.getString("wired_data"); - if(wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.setDelay(data.delay); - this.mode = data.mode; - this.botName = data.bot_name; - this.message = data.message; - this.botSource = (data.botSource != null) - ? WiredBotSourceUtil.normalizeBotSource(data.botSource) + JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class); + if(jsonData != null) { + this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay)); + this.mode = WiredEffectPayloadGuard.mode(jsonData.mode); + this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name); + this.message = jsonData.message != null ? jsonData.message : ""; + this.botSource = (jsonData.botSource != null) + ? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource) : WiredBotSourceUtil.SOURCE_BOT_NAME; } else { - String[] data = wiredData.split(((char) 9) + ""); + String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0]; if (data.length == 4) { - this.setDelay(Integer.parseInt(data[0])); - this.mode = data[1].equalsIgnoreCase("1") ? 1 : 0; - this.botName = data[2]; + this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0])); + this.mode = WiredEffectPayloadGuard.mode(WiredEffectPayloadGuard.parseInt(data[1], 0)); + this.botName = WiredEffectPayloadGuard.text(data[2]); this.message = data[3]; } diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotTalkToHabbo.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotTalkToHabbo.java index c3bc7dfe..7e854823 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotTalkToHabbo.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotTalkToHabbo.java @@ -168,22 +168,22 @@ public class WiredEffectBotTalkToHabbo extends InteractionWiredEffect { public void loadWiredData(ResultSet set, Room room) throws SQLException { String wiredData = set.getString("wired_data"); - if(wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.setDelay(data.delay); - this.mode = data.mode; - this.botName = data.bot_name; - this.message = data.message; - this.userSource = data.userSource; - this.botSource = (data.botSource != null) ? WiredBotSourceUtil.normalizeBotSource(data.botSource) : WiredBotSourceUtil.SOURCE_BOT_NAME; + JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class); + if(jsonData != null) { + this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay)); + this.mode = WiredEffectPayloadGuard.mode(jsonData.mode); + this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name); + this.message = jsonData.message != null ? jsonData.message : ""; + this.userSource = WiredSourceUtil.isDefaultUserSource(jsonData.userSource) ? jsonData.userSource : WiredSourceUtil.SOURCE_TRIGGER; + this.botSource = (jsonData.botSource != null) ? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource) : WiredBotSourceUtil.SOURCE_BOT_NAME; } else { - String[] data = wiredData.split(((char) 9) + ""); + String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0]; if (data.length == 4) { - this.setDelay(Integer.parseInt(data[0])); - this.mode = data[1].equalsIgnoreCase("1") ? 1 : 0; - this.botName = data[2]; + this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0])); + this.mode = WiredEffectPayloadGuard.mode(WiredEffectPayloadGuard.parseInt(data[1], 0)); + this.botName = WiredEffectPayloadGuard.text(data[2]); this.message = data[3]; } diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotTeleport.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotTeleport.java index cb7d6d22..49faad68 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotTeleport.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotTeleport.java @@ -231,37 +231,40 @@ public class WiredEffectBotTeleport extends InteractionWiredEffect { String wiredData = set.getString("wired_data"); - if(wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.setDelay(data.delay); - this.botName = data.bot_name; - this.furniSource = data.furniSource; - this.botSource = (data.botSource != null) - ? WiredBotSourceUtil.normalizeBotSource(data.botSource) + JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class); + if(jsonData != null) { + this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay)); + this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name); + this.furniSource = WiredEffectPayloadGuard.furniSource(jsonData.furniSource); + this.botSource = (jsonData.botSource != null) + ? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource) : WiredBotSourceUtil.SOURCE_BOT_NAME; - for(int itemId : data.items) { - HabboItem item = room.getHabboItem(itemId); + if (jsonData.items != null) { + for(int itemId : jsonData.items) { + HabboItem item = room.getHabboItem(itemId); - if (item != null) - this.items.add(item); + if (item != null) + this.items.add(item); + } } if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) { this.furniSource = WiredSourceUtil.SOURCE_SELECTED; } } else { - String[] wiredDataSplit = set.getString("wired_data").split("\t"); + String[] wiredDataSplit = wiredData != null ? wiredData.split("\t") : new String[0]; if (wiredDataSplit.length >= 2) { - this.setDelay(Integer.parseInt(wiredDataSplit[0])); + this.setDelay(WiredEffectPayloadGuard.parseDelay(wiredDataSplit[0])); String[] data = wiredDataSplit[1].split(";"); if (data.length > 1) { - this.botName = data[0]; + this.botName = WiredEffectPayloadGuard.text(data[0]); for (int i = 1; i < data.length; i++) { - HabboItem item = room.getHabboItem(Integer.parseInt(data[i])); + int itemId = WiredEffectPayloadGuard.parseInt(data[i], 0); + HabboItem item = itemId > 0 ? room.getHabboItem(itemId) : null; if (item != null) this.items.add(item); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotWalkToFurni.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotWalkToFurni.java index 0ccb96b6..6f35f0d0 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotWalkToFurni.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectBotWalkToFurni.java @@ -181,37 +181,40 @@ public class WiredEffectBotWalkToFurni extends InteractionWiredEffect { String wiredData = set.getString("wired_data"); - if(wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.setDelay(data.delay); - this.botName = data.bot_name; - this.furniSource = data.furniSource; - this.botSource = (data.botSource != null) - ? WiredBotSourceUtil.normalizeBotSource(data.botSource) + JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class); + if(jsonData != null) { + this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay)); + this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name); + this.furniSource = WiredEffectPayloadGuard.furniSource(jsonData.furniSource); + this.botSource = (jsonData.botSource != null) + ? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource) : WiredBotSourceUtil.SOURCE_BOT_NAME; - for(int itemId : data.items) { - HabboItem item = room.getHabboItem(itemId); + if (jsonData.items != null) { + for(int itemId : jsonData.items) { + HabboItem item = room.getHabboItem(itemId); - if (item != null) - this.items.add(item); + if (item != null) + this.items.add(item); + } } if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) { this.furniSource = WiredSourceUtil.SOURCE_SELECTED; } } else { - String[] wiredDataSplit = set.getString("wired_data").split("\t"); + String[] wiredDataSplit = wiredData != null ? wiredData.split("\t") : new String[0]; if (wiredDataSplit.length >= 2) { - this.setDelay(Integer.parseInt(wiredDataSplit[0])); + this.setDelay(WiredEffectPayloadGuard.parseDelay(wiredDataSplit[0])); String[] data = wiredDataSplit[1].split(";"); if (data.length > 1) { - this.botName = data[0]; + this.botName = WiredEffectPayloadGuard.text(data[0]); for (int i = 1; i < data.length; i++) { - HabboItem item = room.getHabboItem(Integer.parseInt(data[i])); + int itemId = WiredEffectPayloadGuard.parseInt(data[i], 0); + HabboItem item = itemId > 0 ? room.getHabboItem(itemId) : null; if (item != null) this.items.add(item); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectPayloadGuard.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectPayloadGuard.java new file mode 100644 index 00000000..09fdabc8 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectPayloadGuard.java @@ -0,0 +1,67 @@ +package com.eu.habbo.habbohotel.items.interactions.wired.effects; + +import com.eu.habbo.habbohotel.wired.core.WiredManager; +import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil; + +final class WiredEffectPayloadGuard { + static final int MAX_LOAD_DELAY = 3600; + + private WiredEffectPayloadGuard() { + } + + static int delay(int value) { + if (value < 0) { + return 0; + } + + return Math.min(value, MAX_LOAD_DELAY); + } + + static int parseDelay(String value) { + return delay(parseInt(value, 0)); + } + + static int parseInt(String value, int fallback) { + if (value == null) { + return fallback; + } + + try { + return Integer.parseInt(value.trim()); + } catch (RuntimeException e) { + return fallback; + } + } + + static int mode(int value) { + return value == 1 ? 1 : 0; + } + + static int furniSource(int value) { + switch (value) { + case WiredSourceUtil.SOURCE_TRIGGER: + case WiredSourceUtil.SOURCE_SELECTED: + case WiredSourceUtil.SOURCE_SELECTOR: + case WiredSourceUtil.SOURCE_SIGNAL: + return value; + default: + return WiredSourceUtil.SOURCE_TRIGGER; + } + } + + static String text(String value) { + return value == null ? "" : value.replace("\t", ""); + } + + static T fromJson(String wiredData, Class type) { + if (wiredData == null || !wiredData.startsWith("{")) { + return null; + } + + try { + return WiredManager.getGson().fromJson(wiredData, type); + } catch (RuntimeException e) { + return null; + } + } +} diff --git a/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectPayloadGuardTest.java b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectPayloadGuardTest.java new file mode 100644 index 00000000..b1d1e5e0 --- /dev/null +++ b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectPayloadGuardTest.java @@ -0,0 +1,35 @@ +package com.eu.habbo.habbohotel.items.interactions.wired.effects; + +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.assertNull; + +class WiredEffectPayloadGuardTest { + @Test + void delayIsBoundedForStoredPayloads() { + assertEquals(0, WiredEffectPayloadGuard.delay(-1)); + assertEquals(20, WiredEffectPayloadGuard.delay(20)); + assertEquals(WiredEffectPayloadGuard.MAX_LOAD_DELAY, WiredEffectPayloadGuard.delay(Integer.MAX_VALUE)); + assertEquals(0, WiredEffectPayloadGuard.parseDelay("bad")); + assertEquals(5, WiredEffectPayloadGuard.parseDelay(" 5 ")); + } + + @Test + void modeAndTextFallbacksAreSafe() { + assertEquals(0, WiredEffectPayloadGuard.mode(-1)); + assertEquals(0, WiredEffectPayloadGuard.mode(2)); + assertEquals(1, WiredEffectPayloadGuard.mode(1)); + assertEquals(WiredSourceUtil.SOURCE_TRIGGER, WiredEffectPayloadGuard.furniSource(-1)); + assertEquals(WiredSourceUtil.SOURCE_SELECTED, WiredEffectPayloadGuard.furniSource(WiredSourceUtil.SOURCE_SELECTED)); + assertEquals("", WiredEffectPayloadGuard.text(null)); + assertEquals("botname", WiredEffectPayloadGuard.text("bot\tname")); + } + + @Test + void malformedJsonReturnsNullInsteadOfThrowing() { + assertNull(WiredEffectPayloadGuard.fromJson("{broken", WiredEffectBotTalk.JsonData.class)); + assertNull(WiredEffectPayloadGuard.fromJson(null, WiredEffectBotTalk.JsonData.class)); + } +}