Merge pull request #257 from simoleo89/fix/wired-bot-effect-payloads

fix(wired): bound bot effect payloads
This commit is contained in:
DuckieTM
2026-06-18 12:49:02 +02:00
committed by GitHub
9 changed files with 196 additions and 88 deletions
@@ -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];
}
@@ -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);
@@ -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);
@@ -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];
}
@@ -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];
}
@@ -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);
@@ -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);
@@ -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> T fromJson(String wiredData, Class<T> type) {
if (wiredData == null || !wiredData.startsWith("{")) {
return null;
}
try {
return WiredManager.getGson().fromJson(wiredData, type);
} catch (RuntimeException e) {
return null;
}
}
}
@@ -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));
}
}