diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboCount.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboCount.java index 98010557..ea2d137b 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboCount.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionHabboCount.java @@ -16,6 +16,7 @@ import java.sql.SQLException; public class WiredConditionHabboCount extends InteractionWiredCondition { public static final WiredConditionType type = WiredConditionType.USER_COUNT; + static final int MAX_USER_COUNT_LIMIT = 1000; private int lowerLimit = 0; private int upperLimit = 50; @@ -31,6 +32,10 @@ public class WiredConditionHabboCount extends InteractionWiredCondition { @Override public boolean evaluate(WiredContext ctx) { + if (ctx == null || ctx.room() == null) { + return false; + } + int count = (this.userSource == WiredSourceUtil.SOURCE_TRIGGER) ? ctx.room().getUserCount() : WiredSourceUtil.resolveUsers(ctx, this.userSource).size(); @@ -55,26 +60,40 @@ public class WiredConditionHabboCount extends InteractionWiredCondition { @Override public void loadWiredData(ResultSet set, Room room) throws SQLException { + this.onPickUp(); + String wiredData = set.getString("wired_data"); + if (wiredData == null || wiredData.isEmpty()) { + return; + } if (wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.lowerLimit = data.lowerLimit; - this.upperLimit = data.upperLimit; - this.userSource = data.userSource; - } else { - String[] data = wiredData.split(":"); - - if (data.length >= 2) { - try { - this.lowerLimit = Integer.parseInt(data[0].trim()); - this.upperLimit = Integer.parseInt(data[1].trim()); - } catch (NumberFormatException ignored) { - // malformed legacy data — keep the constructed defaults - } + JsonData data; + try { + data = WiredManager.getGson().fromJson(wiredData, JsonData.class); + } catch (RuntimeException exception) { + this.onPickUp(); + return; } - this.userSource = WiredSourceUtil.SOURCE_TRIGGER; + + if (data == null) { + return; + } + + this.setLimits(data.lowerLimit, data.upperLimit); + this.userSource = this.normalizeUserSource(data.userSource); + return; } + + String[] data = wiredData.split(":"); + if (data.length >= 2) { + try { + this.setLimits(Integer.parseInt(data[0].trim()), Integer.parseInt(data[1].trim())); + } catch (NumberFormatException ignored) { + this.onPickUp(); + } + } + this.userSource = WiredSourceUtil.SOURCE_TRIGGER; } @Override @@ -109,15 +128,36 @@ public class WiredConditionHabboCount extends InteractionWiredCondition { @Override public boolean saveData(WiredSettings settings) { - if(settings.getIntParams().length < 2) return false; - this.lowerLimit = settings.getIntParams()[0]; - this.upperLimit = settings.getIntParams()[1]; + if (settings.getIntParams().length < 2) return false; int[] params = settings.getIntParams(); - this.userSource = (params.length > 2) ? params[2] : WiredSourceUtil.SOURCE_TRIGGER; + this.setLimits(params[0], params[1]); + this.userSource = (params.length > 2) ? this.normalizeUserSource(params[2]) : WiredSourceUtil.SOURCE_TRIGGER; return true; } + void setLimits(int lowerLimit, int upperLimit) { + int normalizedLower = this.normalizeLimit(lowerLimit); + int normalizedUpper = this.normalizeLimit(upperLimit); + + if (normalizedLower > normalizedUpper) { + this.lowerLimit = normalizedUpper; + this.upperLimit = normalizedLower; + return; + } + + this.lowerLimit = normalizedLower; + this.upperLimit = normalizedUpper; + } + + int normalizeLimit(int value) { + return Math.max(0, Math.min(MAX_USER_COUNT_LIMIT, value)); + } + + int normalizeUserSource(int value) { + return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER; + } + static class JsonData { int lowerLimit; int upperLimit; diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionLessTimeElapsed.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionLessTimeElapsed.java index 7086ea7d..d75fb789 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionLessTimeElapsed.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionLessTimeElapsed.java @@ -52,12 +52,13 @@ public class WiredConditionLessTimeElapsed extends InteractionWiredCondition { try { if (wiredData.startsWith("{")) { JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.cycles = data.cycles; + this.cycles = data == null ? 0 : this.normalizeCycles(data.cycles); } else { if (!wiredData.equals("")) - this.cycles = Integer.parseInt(wiredData); + this.cycles = this.normalizeCycles(Integer.parseInt(wiredData)); } } catch (Exception e) { + this.cycles = 0; } } @@ -90,10 +91,14 @@ public class WiredConditionLessTimeElapsed extends InteractionWiredCondition { @Override public boolean saveData(WiredSettings settings) { if(settings.getIntParams().length < 1) return false; - this.cycles = settings.getIntParams()[0]; + this.cycles = this.normalizeCycles(settings.getIntParams()[0]); return true; } + int normalizeCycles(int value) { + return Math.max(0, Math.min(WiredConditionMoreTimeElapsed.MAX_CYCLES, value)); + } + static class JsonData { int cycles; diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionMoreTimeElapsed.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionMoreTimeElapsed.java index 2ae00378..61461bc2 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionMoreTimeElapsed.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionMoreTimeElapsed.java @@ -16,6 +16,7 @@ import java.sql.SQLException; public class WiredConditionMoreTimeElapsed extends InteractionWiredCondition { private static final WiredConditionType type = WiredConditionType.TIME_MORE_THAN; + static final int MAX_CYCLES = 1_000_000; private int cycles; @@ -52,12 +53,13 @@ public class WiredConditionMoreTimeElapsed extends InteractionWiredCondition { try { if (wiredData.startsWith("{")) { JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.cycles = data.cycles; + this.cycles = data == null ? 0 : this.normalizeCycles(data.cycles); } else { if (!wiredData.equals("")) - this.cycles = Integer.parseInt(wiredData); + this.cycles = this.normalizeCycles(Integer.parseInt(wiredData)); } } catch (Exception e) { + this.cycles = 0; } } @@ -90,10 +92,14 @@ public class WiredConditionMoreTimeElapsed extends InteractionWiredCondition { @Override public boolean saveData(WiredSettings settings) { if(settings.getIntParams().length < 1) return false; - this.cycles = settings.getIntParams()[0]; + this.cycles = this.normalizeCycles(settings.getIntParams()[0]); return true; } + int normalizeCycles(int value) { + return Math.max(0, Math.min(MAX_CYCLES, value)); + } + static class JsonData { int cycles; diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionNotHabboCount.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionNotHabboCount.java index e993d19f..0780c440 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionNotHabboCount.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionNotHabboCount.java @@ -6,8 +6,8 @@ import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings; import com.eu.habbo.habbohotel.rooms.Room; import com.eu.habbo.habbohotel.rooms.RoomUnit; import com.eu.habbo.habbohotel.wired.WiredConditionType; -import com.eu.habbo.habbohotel.wired.core.WiredManager; import com.eu.habbo.habbohotel.wired.core.WiredContext; +import com.eu.habbo.habbohotel.wired.core.WiredManager; import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil; import com.eu.habbo.messages.ServerMessage; @@ -31,6 +31,10 @@ public class WiredConditionNotHabboCount extends InteractionWiredCondition { @Override public boolean evaluate(WiredContext ctx) { + if (ctx == null || ctx.room() == null) { + return false; + } + int count = (this.userSource == WiredSourceUtil.SOURCE_TRIGGER) ? ctx.room().getUserCount() : WiredSourceUtil.resolveUsers(ctx, this.userSource).size(); @@ -55,25 +59,40 @@ public class WiredConditionNotHabboCount extends InteractionWiredCondition { @Override public void loadWiredData(ResultSet set, Room room) throws SQLException { + this.onPickUp(); + String wiredData = set.getString("wired_data"); + if (wiredData == null || wiredData.isEmpty()) { + return; + } if (wiredData.startsWith("{")) { - WiredConditionHabboCount.JsonData data = WiredManager.getGson().fromJson(wiredData, WiredConditionHabboCount.JsonData.class); - this.lowerLimit = data.lowerLimit; - this.upperLimit = data.upperLimit; - this.userSource = data.userSource; - } else { - String[] data = wiredData.split(":"); - if (data.length >= 2) { - try { - this.lowerLimit = Integer.parseInt(data[0].trim()); - this.upperLimit = Integer.parseInt(data[1].trim()); - } catch (NumberFormatException ignored) { - // malformed legacy data — keep the constructed defaults - } + WiredConditionHabboCount.JsonData data; + try { + data = WiredManager.getGson().fromJson(wiredData, WiredConditionHabboCount.JsonData.class); + } catch (RuntimeException exception) { + this.onPickUp(); + return; } - this.userSource = WiredSourceUtil.SOURCE_TRIGGER; + + if (data == null) { + return; + } + + this.setLimits(data.lowerLimit, data.upperLimit); + this.userSource = this.normalizeUserSource(data.userSource); + return; } + + String[] data = wiredData.split(":"); + if (data.length >= 2) { + try { + this.setLimits(Integer.parseInt(data[0].trim()), Integer.parseInt(data[1].trim())); + } catch (NumberFormatException ignored) { + this.onPickUp(); + } + } + this.userSource = WiredSourceUtil.SOURCE_TRIGGER; } @Override @@ -108,15 +127,36 @@ public class WiredConditionNotHabboCount extends InteractionWiredCondition { @Override public boolean saveData(WiredSettings settings) { - if(settings.getIntParams().length < 2) return false; - this.lowerLimit = settings.getIntParams()[0]; - this.upperLimit = settings.getIntParams()[1]; + if (settings.getIntParams().length < 2) return false; int[] params = settings.getIntParams(); - this.userSource = (params.length > 2) ? params[2] : WiredSourceUtil.SOURCE_TRIGGER; + this.setLimits(params[0], params[1]); + this.userSource = (params.length > 2) ? this.normalizeUserSource(params[2]) : WiredSourceUtil.SOURCE_TRIGGER; return true; } + void setLimits(int lowerLimit, int upperLimit) { + int normalizedLower = this.normalizeLimit(lowerLimit); + int normalizedUpper = this.normalizeLimit(upperLimit); + + if (normalizedLower > normalizedUpper) { + this.lowerLimit = normalizedUpper; + this.upperLimit = normalizedLower; + return; + } + + this.lowerLimit = normalizedLower; + this.upperLimit = normalizedUpper; + } + + int normalizeLimit(int value) { + return Math.max(0, Math.min(WiredConditionHabboCount.MAX_USER_COUNT_LIMIT, value)); + } + + int normalizeUserSource(int value) { + return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER; + } + static class JsonData { int lowerLimit; int upperLimit; diff --git a/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionCountTimePayloadGuardTest.java b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionCountTimePayloadGuardTest.java new file mode 100644 index 00000000..336bc2a6 --- /dev/null +++ b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionCountTimePayloadGuardTest.java @@ -0,0 +1,50 @@ +package com.eu.habbo.habbohotel.items.interactions.wired.conditions; + +import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class WiredConditionCountTimePayloadGuardTest { + @Test + void userCountLimitsAndSourcesAreBounded() { + WiredConditionHabboCount condition = new WiredConditionHabboCount(1, 1, null, "", 0, 0); + + assertEquals(0, condition.normalizeLimit(-20)); + assertEquals(25, condition.normalizeLimit(25)); + assertEquals(WiredConditionHabboCount.MAX_USER_COUNT_LIMIT, condition.normalizeLimit(50_000)); + assertEquals(WiredSourceUtil.SOURCE_SIGNAL, condition.normalizeUserSource(WiredSourceUtil.SOURCE_SIGNAL)); + assertEquals(WiredSourceUtil.SOURCE_TRIGGER, condition.normalizeUserSource(-55)); + } + + @Test + void invertedUserCountRangesAreSorted() { + WiredConditionHabboCount condition = new WiredConditionHabboCount(1, 1, null, "", 0, 0); + + condition.setLimits(80, 10); + + assertEquals("{\"lowerLimit\":10,\"upperLimit\":80,\"userSource\":0}", condition.getWiredData()); + } + + @Test + void notUserCountUsesSameBounds() { + WiredConditionNotHabboCount condition = new WiredConditionNotHabboCount(1, 1, null, "", 0, 0); + + assertEquals(0, condition.normalizeLimit(-1)); + assertEquals(WiredConditionHabboCount.MAX_USER_COUNT_LIMIT, condition.normalizeLimit(9_999)); + assertEquals(WiredSourceUtil.SOURCE_CLICKED_USER, condition.normalizeUserSource(WiredSourceUtil.SOURCE_CLICKED_USER)); + assertEquals(WiredSourceUtil.SOURCE_TRIGGER, condition.normalizeUserSource(777)); + } + + @Test + void elapsedTimeCyclesAreBounded() { + WiredConditionMoreTimeElapsed more = new WiredConditionMoreTimeElapsed(1, 1, null, "", 0, 0); + WiredConditionLessTimeElapsed less = new WiredConditionLessTimeElapsed(1, 1, null, "", 0, 0); + + assertEquals(0, more.normalizeCycles(-1)); + assertEquals(42, more.normalizeCycles(42)); + assertEquals(WiredConditionMoreTimeElapsed.MAX_CYCLES, more.normalizeCycles(Integer.MAX_VALUE)); + assertEquals(0, less.normalizeCycles(-1)); + assertEquals(WiredConditionMoreTimeElapsed.MAX_CYCLES, less.normalizeCycles(Integer.MAX_VALUE)); + } +}