fix(wired): bound bot effect payloads

This commit is contained in:
simoleo89
2026-06-17 20:18:48 +02:00
parent 416d0bb088
commit 60b998f909
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 { public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data"); String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) { JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class);
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); if(jsonData != null) {
this.setDelay(data.delay); this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay));
this.botName = data.bot_name; this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name);
this.botLook = data.look; this.botLook = jsonData.look != null ? jsonData.look : "";
this.botSource = (data.botSource != null) this.botSource = (jsonData.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(data.botSource) ? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource)
: WiredBotSourceUtil.SOURCE_BOT_NAME; : WiredBotSourceUtil.SOURCE_BOT_NAME;
} }
else { else {
String[] data = wiredData.split(((char) 9) + ""); String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0];
if (data.length >= 3) { if (data.length >= 3) {
this.setDelay(Integer.parseInt(data[0])); this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0]));
this.botName = data[1]; this.botName = WiredEffectPayloadGuard.text(data[1]);
this.botLook = data[2]; this.botLook = data[2];
} }
@@ -143,23 +143,23 @@ public class WiredEffectBotFollowHabbo extends InteractionWiredEffect {
public void loadWiredData(ResultSet set, Room room) throws SQLException { public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data"); String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) { JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class);
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); if(jsonData != null) {
this.setDelay(data.delay); this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay));
this.mode = data.mode; this.mode = WiredEffectPayloadGuard.mode(jsonData.mode);
this.botName = data.bot_name; this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name);
this.userSource = data.userSource; this.userSource = WiredSourceUtil.isDefaultUserSource(jsonData.userSource) ? jsonData.userSource : WiredSourceUtil.SOURCE_TRIGGER;
this.botSource = (data.botSource != null) this.botSource = (jsonData.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(data.botSource) ? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource)
: WiredBotSourceUtil.SOURCE_BOT_NAME; : WiredBotSourceUtil.SOURCE_BOT_NAME;
} }
else { else {
String[] data = wiredData.split(((char) 9) + ""); String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0];
if (data.length == 3) { if (data.length == 3) {
this.setDelay(Integer.parseInt(data[0])); this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0]));
this.mode = (data[1].equalsIgnoreCase("1") ? 1 : 0); this.mode = WiredEffectPayloadGuard.mode(WiredEffectPayloadGuard.parseInt(data[1], 0));
this.botName = data[2]; this.botName = WiredEffectPayloadGuard.text(data[2]);
} }
this.needsUpdate(true); this.needsUpdate(true);
@@ -153,23 +153,23 @@ public class WiredEffectBotGiveHandItem extends InteractionWiredEffect {
public void loadWiredData(ResultSet set, Room room) throws SQLException { public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data"); String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) { JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class);
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); if(jsonData != null) {
this.setDelay(data.delay); this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay));
this.itemId = this.normalizeHandItem(data.item_id); this.itemId = this.normalizeHandItem(jsonData.item_id);
this.botName = data.bot_name; this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name);
this.userSource = this.normalizeUserSource(data.userSource); this.userSource = this.normalizeUserSource(jsonData.userSource);
this.botSource = ((data.botSource == WiredSourceUtil.SOURCE_TRIGGER) && this.botName != null && !this.botName.isEmpty()) this.botSource = ((jsonData.botSource == WiredSourceUtil.SOURCE_TRIGGER) && this.botName != null && !this.botName.isEmpty())
? BOT_SOURCE_NAME ? BOT_SOURCE_NAME
: this.normalizeBotSource(data.botSource); : this.normalizeBotSource(jsonData.botSource);
} }
else { else {
String[] data = wiredData.split(((char) 9) + ""); String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0];
if (data.length == 3) { if (data.length == 3) {
this.setDelay(Integer.parseInt(data[0])); this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0]));
this.itemId = this.normalizeHandItem(Integer.parseInt(data[1])); this.itemId = this.normalizeHandItem(WiredEffectPayloadGuard.parseInt(data[1], 0));
this.botName = data[2]; this.botName = WiredEffectPayloadGuard.text(data[2]);
} }
this.needsUpdate(true); this.needsUpdate(true);
@@ -144,23 +144,23 @@ public class WiredEffectBotTalk extends InteractionWiredEffect {
public void loadWiredData(ResultSet set, Room room) throws SQLException { public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data"); String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) { JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class);
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); if(jsonData != null) {
this.setDelay(data.delay); this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay));
this.mode = data.mode; this.mode = WiredEffectPayloadGuard.mode(jsonData.mode);
this.botName = data.bot_name; this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name);
this.message = data.message; this.message = jsonData.message != null ? jsonData.message : "";
this.botSource = (data.botSource != null) this.botSource = (jsonData.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(data.botSource) ? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource)
: WiredBotSourceUtil.SOURCE_BOT_NAME; : WiredBotSourceUtil.SOURCE_BOT_NAME;
} }
else { else {
String[] data = wiredData.split(((char) 9) + ""); String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0];
if (data.length == 4) { if (data.length == 4) {
this.setDelay(Integer.parseInt(data[0])); this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0]));
this.mode = data[1].equalsIgnoreCase("1") ? 1 : 0; this.mode = WiredEffectPayloadGuard.mode(WiredEffectPayloadGuard.parseInt(data[1], 0));
this.botName = data[2]; this.botName = WiredEffectPayloadGuard.text(data[2]);
this.message = data[3]; this.message = data[3];
} }
@@ -168,22 +168,22 @@ public class WiredEffectBotTalkToHabbo extends InteractionWiredEffect {
public void loadWiredData(ResultSet set, Room room) throws SQLException { public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data"); String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) { JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class);
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); if(jsonData != null) {
this.setDelay(data.delay); this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay));
this.mode = data.mode; this.mode = WiredEffectPayloadGuard.mode(jsonData.mode);
this.botName = data.bot_name; this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name);
this.message = data.message; this.message = jsonData.message != null ? jsonData.message : "";
this.userSource = data.userSource; this.userSource = WiredSourceUtil.isDefaultUserSource(jsonData.userSource) ? jsonData.userSource : WiredSourceUtil.SOURCE_TRIGGER;
this.botSource = (data.botSource != null) ? WiredBotSourceUtil.normalizeBotSource(data.botSource) : WiredBotSourceUtil.SOURCE_BOT_NAME; this.botSource = (jsonData.botSource != null) ? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource) : WiredBotSourceUtil.SOURCE_BOT_NAME;
} }
else { else {
String[] data = wiredData.split(((char) 9) + ""); String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0];
if (data.length == 4) { if (data.length == 4) {
this.setDelay(Integer.parseInt(data[0])); this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0]));
this.mode = data[1].equalsIgnoreCase("1") ? 1 : 0; this.mode = WiredEffectPayloadGuard.mode(WiredEffectPayloadGuard.parseInt(data[1], 0));
this.botName = data[2]; this.botName = WiredEffectPayloadGuard.text(data[2]);
this.message = data[3]; this.message = data[3];
} }
@@ -231,37 +231,40 @@ public class WiredEffectBotTeleport extends InteractionWiredEffect {
String wiredData = set.getString("wired_data"); String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) { JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class);
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); if(jsonData != null) {
this.setDelay(data.delay); this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay));
this.botName = data.bot_name; this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name);
this.furniSource = data.furniSource; this.furniSource = WiredEffectPayloadGuard.furniSource(jsonData.furniSource);
this.botSource = (data.botSource != null) this.botSource = (jsonData.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(data.botSource) ? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource)
: WiredBotSourceUtil.SOURCE_BOT_NAME; : WiredBotSourceUtil.SOURCE_BOT_NAME;
for(int itemId : data.items) { if (jsonData.items != null) {
HabboItem item = room.getHabboItem(itemId); for(int itemId : jsonData.items) {
HabboItem item = room.getHabboItem(itemId);
if (item != null) if (item != null)
this.items.add(item); this.items.add(item);
}
} }
if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) { if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED; this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
} }
} }
else { else {
String[] wiredDataSplit = set.getString("wired_data").split("\t"); String[] wiredDataSplit = wiredData != null ? wiredData.split("\t") : new String[0];
if (wiredDataSplit.length >= 2) { if (wiredDataSplit.length >= 2) {
this.setDelay(Integer.parseInt(wiredDataSplit[0])); this.setDelay(WiredEffectPayloadGuard.parseDelay(wiredDataSplit[0]));
String[] data = wiredDataSplit[1].split(";"); String[] data = wiredDataSplit[1].split(";");
if (data.length > 1) { if (data.length > 1) {
this.botName = data[0]; this.botName = WiredEffectPayloadGuard.text(data[0]);
for (int i = 1; i < data.length; i++) { 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) if (item != null)
this.items.add(item); this.items.add(item);
@@ -181,37 +181,40 @@ public class WiredEffectBotWalkToFurni extends InteractionWiredEffect {
String wiredData = set.getString("wired_data"); String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) { JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class);
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); if(jsonData != null) {
this.setDelay(data.delay); this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay));
this.botName = data.bot_name; this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name);
this.furniSource = data.furniSource; this.furniSource = WiredEffectPayloadGuard.furniSource(jsonData.furniSource);
this.botSource = (data.botSource != null) this.botSource = (jsonData.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(data.botSource) ? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource)
: WiredBotSourceUtil.SOURCE_BOT_NAME; : WiredBotSourceUtil.SOURCE_BOT_NAME;
for(int itemId : data.items) { if (jsonData.items != null) {
HabboItem item = room.getHabboItem(itemId); for(int itemId : jsonData.items) {
HabboItem item = room.getHabboItem(itemId);
if (item != null) if (item != null)
this.items.add(item); this.items.add(item);
}
} }
if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) { if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED; this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
} }
} }
else { else {
String[] wiredDataSplit = set.getString("wired_data").split("\t"); String[] wiredDataSplit = wiredData != null ? wiredData.split("\t") : new String[0];
if (wiredDataSplit.length >= 2) { if (wiredDataSplit.length >= 2) {
this.setDelay(Integer.parseInt(wiredDataSplit[0])); this.setDelay(WiredEffectPayloadGuard.parseDelay(wiredDataSplit[0]));
String[] data = wiredDataSplit[1].split(";"); String[] data = wiredDataSplit[1].split(";");
if (data.length > 1) { if (data.length > 1) {
this.botName = data[0]; this.botName = WiredEffectPayloadGuard.text(data[0]);
for (int i = 1; i < data.length; i++) { 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) if (item != null)
this.items.add(item); 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));
}
}