diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectTeleport.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectTeleport.java index 3c0207d1..accac947 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectTeleport.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectTeleport.java @@ -269,23 +269,26 @@ public class WiredEffectTeleport extends InteractionWiredEffect { this.items = new ArrayList<>(); String wiredData = set.getString("wired_data"); - if (wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.setDelay(data.delay); - this.fastTeleport = data.fastTeleport; - this.furniSource = data.furniSource; - this.userSource = data.userSource; - for (Integer id: data.itemIds) { - HabboItem item = room.getHabboItem(id); - if (item != null) { - this.items.add(item); + JsonData jsonData = WiredMovementPayloadGuard.fromJson(wiredData, JsonData.class); + if (jsonData != null) { + this.setDelay(WiredMovementPayloadGuard.delay(jsonData.delay)); + this.fastTeleport = jsonData.fastTeleport; + this.furniSource = WiredMovementPayloadGuard.furniSource(jsonData.furniSource); + this.userSource = WiredMovementPayloadGuard.userSource(jsonData.userSource); + if (jsonData.itemIds != null) { + for (Integer id: jsonData.itemIds) { + if (id == null) continue; + HabboItem item = room.getHabboItem(id); + if (item != null) { + this.items.add(item); + } } } if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) { this.furniSource = WiredSourceUtil.SOURCE_SELECTED; } } else { - String[] wiredDataOld = wiredData.split("\t"); + String[] wiredDataOld = wiredData != null ? wiredData.split("\t") : new String[0]; if (wiredDataOld.length >= 1) { this.setDelay(WiredLegacyDataGuard.parseDelay(wiredDataOld[0])); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectToggleFurni.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectToggleFurni.java index 19d9fd3d..fe90dc28 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectToggleFurni.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectToggleFurni.java @@ -252,12 +252,13 @@ public class WiredEffectToggleFurni extends InteractionWiredEffect { this.items.clear(); String wiredData = set.getString("wired_data"); - if (wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.setDelay(data.delay); - this.toggleType = normalizeToggleType(data.toggleType); - this.furniSource = data.furniSource; - for (Integer id: data.itemIds) { + JsonData jsonData = WiredMovementPayloadGuard.fromJson(wiredData, JsonData.class); + if (jsonData != null) { + this.setDelay(WiredMovementPayloadGuard.delay(jsonData.delay)); + this.toggleType = normalizeToggleType(jsonData.toggleType); + this.furniSource = WiredMovementPayloadGuard.furniSource(jsonData.furniSource); + if (jsonData.itemIds != null) for (Integer id: jsonData.itemIds) { + if (id == null) continue; HabboItem item = room.getHabboItem(id); if (item instanceof InteractionFreezeBlock || item instanceof InteractionFreezeTile || item instanceof InteractionCrackable) { @@ -272,7 +273,7 @@ public class WiredEffectToggleFurni extends InteractionWiredEffect { this.furniSource = WiredSourceUtil.SOURCE_SELECTED; } } else { - String[] wiredDataOld = wiredData.split("\t"); + String[] wiredDataOld = wiredData != null ? wiredData.split("\t") : new String[0]; if (wiredDataOld.length >= 1) { this.setDelay(WiredLegacyDataGuard.parseDelay(wiredDataOld[0])); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectToggleRandom.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectToggleRandom.java index 32ba5870..a4c97d19 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectToggleRandom.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectToggleRandom.java @@ -230,13 +230,14 @@ public class WiredEffectToggleRandom extends InteractionWiredEffect { this.items.clear(); String wiredData = set.getString("wired_data"); - if (wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.setDelay(data.delay); - this.furniSource = data.furniSource; - for (Integer id: data.itemIds) { + JsonData jsonData = WiredMovementPayloadGuard.fromJson(wiredData, JsonData.class); + if (jsonData != null) { + this.setDelay(WiredMovementPayloadGuard.delay(jsonData.delay)); + this.furniSource = WiredMovementPayloadGuard.furniSource(jsonData.furniSource); + if (jsonData.itemIds != null) for (Integer id: jsonData.itemIds) { + if (id == null) continue; HabboItem item = room.getHabboItem(id); - + if (item instanceof InteractionFreezeBlock || item instanceof InteractionGameTimer || item instanceof InteractionCrackable) continue; @@ -247,15 +248,16 @@ public class WiredEffectToggleRandom extends InteractionWiredEffect { this.furniSource = WiredSourceUtil.SOURCE_SELECTED; } } else { - String[] wiredDataOld = wiredData.split("\t"); + String[] wiredDataOld = wiredData != null ? wiredData.split("\t") : new String[0]; if (wiredDataOld.length >= 1) { - this.setDelay(Integer.parseInt(wiredDataOld[0])); + this.setDelay(WiredMovementPayloadGuard.parseDelay(wiredDataOld[0])); } if (wiredDataOld.length == 2) { if (wiredDataOld[1].contains(";")) { for (String s : wiredDataOld[1].split(";")) { - HabboItem item = room.getHabboItem(Integer.parseInt(s)); + int itemId = WiredMovementPayloadGuard.parseInt(s, 0); + HabboItem item = itemId > 0 ? room.getHabboItem(itemId) : null; if (item instanceof InteractionFreezeBlock || item instanceof InteractionGameTimer || item instanceof InteractionCrackable) continue; diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectTriggerStacks.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectTriggerStacks.java index 2dda07c8..1ff86856 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectTriggerStacks.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectTriggerStacks.java @@ -178,29 +178,33 @@ public class WiredEffectTriggerStacks extends InteractionWiredEffect { this.items = new THashSet<>(); String wiredData = set.getString("wired_data"); - if (wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.setDelay(data.delay); - this.furniSource = data.furniSource; - for (Integer id: data.itemIds) { - HabboItem item = room.getHabboItem(id); - if (item != null) { - this.items.add(item); + JsonData jsonData = WiredMovementPayloadGuard.fromJson(wiredData, JsonData.class); + if (jsonData != null) { + this.setDelay(WiredMovementPayloadGuard.delay(jsonData.delay)); + this.furniSource = WiredMovementPayloadGuard.furniSource(jsonData.furniSource); + if (jsonData.itemIds != null) { + for (Integer id: jsonData.itemIds) { + if (id == null) continue; + HabboItem item = room.getHabboItem(id); + if (item != null) { + this.items.add(item); + } } } if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) { this.furniSource = WiredSourceUtil.SOURCE_SELECTED; } } else { - String[] wiredDataOld = wiredData.split("\t"); + String[] wiredDataOld = wiredData != null ? wiredData.split("\t") : new String[0]; if (wiredDataOld.length >= 1) { - this.setDelay(Integer.parseInt(wiredDataOld[0])); + this.setDelay(WiredMovementPayloadGuard.parseDelay(wiredDataOld[0])); } if (wiredDataOld.length == 2) { if (wiredDataOld[1].contains(";")) { for (String s : wiredDataOld[1].split(";")) { - HabboItem item = room.getHabboItem(Integer.parseInt(s)); + int itemId = WiredMovementPayloadGuard.parseInt(s, 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/WiredMovementPayloadGuard.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredMovementPayloadGuard.java new file mode 100644 index 00000000..b80a21f3 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredMovementPayloadGuard.java @@ -0,0 +1,63 @@ +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 WiredMovementPayloadGuard { + static final int MAX_LOAD_DELAY = 3600; + + private WiredMovementPayloadGuard() { + } + + 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 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 int userSource(int value) { + return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER; + } + + 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/WiredMovementPayloadGuardTest.java b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredMovementPayloadGuardTest.java new file mode 100644 index 00000000..7b52ecb4 --- /dev/null +++ b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredMovementPayloadGuardTest.java @@ -0,0 +1,33 @@ +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 WiredMovementPayloadGuardTest { + @Test + void delayAndIntegersAreBounded() { + assertEquals(0, WiredMovementPayloadGuard.delay(-100)); + assertEquals(25, WiredMovementPayloadGuard.parseDelay("25")); + assertEquals(0, WiredMovementPayloadGuard.parseDelay("bad")); + assertEquals(WiredMovementPayloadGuard.MAX_LOAD_DELAY, WiredMovementPayloadGuard.delay(Integer.MAX_VALUE)); + assertEquals(7, WiredMovementPayloadGuard.parseInt(" 7 ", 0)); + assertEquals(3, WiredMovementPayloadGuard.parseInt("oops", 3)); + } + + @Test + void sourceValuesFallbackToTriggerWhenInvalid() { + assertEquals(WiredSourceUtil.SOURCE_TRIGGER, WiredMovementPayloadGuard.furniSource(-1)); + assertEquals(WiredSourceUtil.SOURCE_SELECTED, WiredMovementPayloadGuard.furniSource(WiredSourceUtil.SOURCE_SELECTED)); + assertEquals(WiredSourceUtil.SOURCE_TRIGGER, WiredMovementPayloadGuard.userSource(999)); + assertEquals(WiredSourceUtil.SOURCE_SELECTOR, WiredMovementPayloadGuard.userSource(WiredSourceUtil.SOURCE_SELECTOR)); + } + + @Test + void malformedJsonDoesNotThrow() { + assertNull(WiredMovementPayloadGuard.fromJson("{broken", WiredEffectTeleport.JsonData.class)); + assertNull(WiredMovementPayloadGuard.fromJson(null, WiredEffectTeleport.JsonData.class)); + } +}