diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectAdjustClock.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectAdjustClock.java index 183eec7d..05f43b74 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectAdjustClock.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectAdjustClock.java @@ -93,16 +93,17 @@ public class WiredEffectAdjustClock extends InteractionWiredEffect { this.items.clear(); String wiredData = set.getString("wired_data"); - if (wiredData != null && wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.setDelay(data.delay); - this.operator = this.normalizeOperator(data.operator); - this.furniSource = data.furniSource; - this.minutes = this.normalizeMinutes(data.minutes); - this.halfSecondSteps = this.normalizeHalfSecondSteps(data.halfSecondSteps); + JsonData jsonData = WiredUtilityPayloadGuard.fromJson(wiredData, JsonData.class); + if (jsonData != null) { + this.setDelay(WiredUtilityPayloadGuard.delay(jsonData.delay)); + this.operator = this.normalizeOperator(jsonData.operator); + this.furniSource = WiredUtilityPayloadGuard.furniSource(jsonData.furniSource); + this.minutes = this.normalizeMinutes(jsonData.minutes); + this.halfSecondSteps = this.normalizeHalfSecondSteps(jsonData.halfSecondSteps); - if (data.itemIds != null) { - for (Integer id : data.itemIds) { + if (jsonData.itemIds != null) { + for (Integer id : jsonData.itemIds) { + if (id == null) continue; HabboItem item = room.getHabboItem(id); if (item != null) { diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectChangeVariableValue.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectChangeVariableValue.java index 5e7e5c37..4d5b1b8f 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectChangeVariableValue.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectChangeVariableValue.java @@ -298,7 +298,7 @@ public class WiredEffectChangeVariableValue extends InteractionWiredEffect { String wiredData = set.getString("wired_data"); if (wiredData == null || wiredData.isEmpty() || !wiredData.startsWith("{")) return; - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); + JsonData data = WiredUtilityPayloadGuard.fromJson(wiredData, JsonData.class); if (data == null) return; this.destinationTargetType = normalizeTargetType(data.destinationTargetType); @@ -312,7 +312,7 @@ public class WiredEffectChangeVariableValue extends InteractionWiredEffect { this.destinationFurniSource = normalizeDestinationFurniSource(data.destinationFurniSource); this.referenceUserSource = normalizeUserSource(data.referenceUserSource); this.referenceFurniSource = normalizeReferenceFurniSource(data.referenceFurniSource); - this.setDelay(Math.max(0, data.delay)); + this.setDelay(WiredUtilityPayloadGuard.delay(data.delay)); if (room != null) { try { diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectRemoveVariable.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectRemoveVariable.java index d2812e61..2f574a73 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectRemoveVariable.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectRemoveVariable.java @@ -260,14 +260,14 @@ public class WiredEffectRemoveVariable extends InteractionWiredEffect { } if (wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); + JsonData data = WiredUtilityPayloadGuard.fromJson(wiredData, JsonData.class); if (data != null) { this.variableItemId = Math.max(0, data.variableItemId); this.targetType = normalizeTargetType(data.targetType); this.userSource = normalizeUserSource(data.userSource); this.furniSource = normalizeFurniSource(data.furniSource); - this.setDelay(Math.max(0, data.delay)); + this.setDelay(WiredUtilityPayloadGuard.delay(data.delay)); if (room != null && data.selectedFurniIds != null) { for (Integer itemId : data.selectedFurniIds) { diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectResetTimers.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectResetTimers.java index e0abd1da..e4cb1b89 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectResetTimers.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectResetTimers.java @@ -96,19 +96,16 @@ public class WiredEffectResetTimers 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.delay = data.delay; + JsonData jsonData = WiredUtilityPayloadGuard.fromJson(wiredData, JsonData.class); + if (jsonData != null) { + this.delay = WiredUtilityPayloadGuard.delay(jsonData.delay); } else { - try { - if (!wiredData.equals("")) { - this.delay = Integer.parseInt(wiredData); - } - } catch (Exception e) { + if (wiredData != null && !wiredData.equals("")) { + this.delay = WiredUtilityPayloadGuard.parseDelay(wiredData); } } - this.setDelay(this.delay); + this.setDelay(WiredUtilityPayloadGuard.delay(this.delay)); } @Override diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectSendSignal.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectSendSignal.java index 99a14b67..27efef2f 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectSendSignal.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectSendSignal.java @@ -350,9 +350,9 @@ public class WiredEffectSendSignal extends InteractionWiredEffect { this.forwardItems = new THashSet<>(); String wiredData = set.getString("wired_data"); - if (wiredData != null && wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.setDelay(data.delay); + JsonData data = WiredUtilityPayloadGuard.fromJson(wiredData, JsonData.class); + if (data != null) { + this.setDelay(WiredUtilityPayloadGuard.delay(data.delay)); this.antennaSource = data.antennaSource; this.furniForward = normalizeSource(data.furniForward); this.userForward = normalizeSource(data.userForward); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectSetAltitude.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectSetAltitude.java index 9233daed..6675e54b 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectSetAltitude.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectSetAltitude.java @@ -100,15 +100,16 @@ public class WiredEffectSetAltitude extends InteractionWiredEffect { this.items.clear(); String wiredData = set.getString("wired_data"); - if (wiredData != null && wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.setDelay(data.delay); - this.operator = this.normalizeOperator(data.operator); - this.altitude = this.parseAltitudeOrDefault(data.altitude); - this.furniSource = data.furniSource; + JsonData jsonData = WiredUtilityPayloadGuard.fromJson(wiredData, JsonData.class); + if (jsonData != null) { + this.setDelay(WiredUtilityPayloadGuard.delay(jsonData.delay)); + this.operator = this.normalizeOperator(jsonData.operator); + this.altitude = this.parseAltitudeOrDefault(jsonData.altitude); + this.furniSource = WiredUtilityPayloadGuard.furniSource(jsonData.furniSource); - if (data.itemIds != null) { - for (Integer id : data.itemIds) { + if (jsonData.itemIds != null) { + for (Integer id : jsonData.itemIds) { + if (id == null) continue; HabboItem item = room.getHabboItem(id); if (item != null) { diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectWhisper.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectWhisper.java index a2b858f4..25b7aa83 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectWhisper.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectWhisper.java @@ -272,22 +272,23 @@ public class WiredEffectWhisper 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.message = data.message; - this.userSource = (data.userSource != null) ? data.userSource : WiredSourceUtil.SOURCE_TRIGGER; - this.visibilitySelection = (data.visibilitySelection != null && data.visibilitySelection == VISIBILITY_ALL_ROOM_USERS) + JsonData jsonData = WiredUtilityPayloadGuard.fromJson(wiredData, JsonData.class); + if(jsonData != null) { + this.setDelay(WiredUtilityPayloadGuard.delay(jsonData.delay)); + this.message = WiredUtilityPayloadGuard.text(jsonData.message); + this.userSource = (jsonData.userSource != null) ? WiredUtilityPayloadGuard.userSource(jsonData.userSource) : WiredSourceUtil.SOURCE_TRIGGER; + this.visibilitySelection = (jsonData.visibilitySelection != null && jsonData.visibilitySelection == VISIBILITY_ALL_ROOM_USERS) ? VISIBILITY_ALL_ROOM_USERS : VISIBILITY_SOURCE_USERS; - this.bubbleStyle = (data.bubbleStyle != null) ? data.bubbleStyle : RoomChatMessageBubbles.WIRED.getType(); + this.bubbleStyle = (jsonData.bubbleStyle != null) ? jsonData.bubbleStyle : RoomChatMessageBubbles.WIRED.getType(); } else { this.message = ""; - if (wiredData.split("\t").length >= 2) { - super.setDelay(Integer.parseInt(wiredData.split("\t")[0])); - this.message = wiredData.split("\t")[1]; + String[] wiredDataSplit = wiredData != null ? wiredData.split("\t") : new String[0]; + if (wiredDataSplit.length >= 2) { + super.setDelay(WiredUtilityPayloadGuard.parseDelay(wiredDataSplit[0])); + this.message = wiredDataSplit[1]; } this.userSource = WiredSourceUtil.SOURCE_TRIGGER; diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredUtilityPayloadGuard.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredUtilityPayloadGuard.java new file mode 100644 index 00000000..a74184ae --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredUtilityPayloadGuard.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 WiredUtilityPayloadGuard { + static final int MAX_LOAD_DELAY = 3600; + + private WiredUtilityPayloadGuard() { + } + + 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 userSource(int value) { + return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER; + } + + 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; + } + + 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/WiredUtilityPayloadGuardTest.java b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredUtilityPayloadGuardTest.java new file mode 100644 index 00000000..716afb02 --- /dev/null +++ b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredUtilityPayloadGuardTest.java @@ -0,0 +1,32 @@ +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 WiredUtilityPayloadGuardTest { + @Test + void clampsDelayAndParsesLegacyNumbers() { + assertEquals(0, WiredUtilityPayloadGuard.delay(-1)); + assertEquals(20, WiredUtilityPayloadGuard.parseDelay("20")); + assertEquals(0, WiredUtilityPayloadGuard.parseDelay("bad")); + assertEquals(WiredUtilityPayloadGuard.MAX_LOAD_DELAY, WiredUtilityPayloadGuard.delay(Integer.MAX_VALUE)); + } + + @Test + void normalizesSourcesAndText() { + assertEquals(WiredSourceUtil.SOURCE_TRIGGER, WiredUtilityPayloadGuard.userSource(999)); + assertEquals(WiredSourceUtil.SOURCE_SELECTOR, WiredUtilityPayloadGuard.userSource(WiredSourceUtil.SOURCE_SELECTOR)); + assertEquals(WiredSourceUtil.SOURCE_TRIGGER, WiredUtilityPayloadGuard.furniSource(-1)); + assertEquals(WiredSourceUtil.SOURCE_SELECTED, WiredUtilityPayloadGuard.furniSource(WiredSourceUtil.SOURCE_SELECTED)); + assertEquals("", WiredUtilityPayloadGuard.text(null)); + } + + @Test + void malformedJsonReturnsNull() { + assertNull(WiredUtilityPayloadGuard.fromJson("{broken", WiredEffectResetTimers.JsonData.class)); + assertNull(WiredUtilityPayloadGuard.fromJson(null, WiredEffectResetTimers.JsonData.class)); + } +}