From 7869938d98c5a815473706e5c18a6a935ff9b171 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Wed, 17 Jun 2026 18:27:36 +0200 Subject: [PATCH] fix(wired): bound condition inputs --- .../conditions/WiredConditionHabboCount.java | 19 ++++--- .../conditions/WiredConditionInputGuard.java | 57 +++++++++++++++++++ .../WiredConditionLessTimeElapsed.java | 6 +- .../WiredConditionMoreTimeElapsed.java | 6 +- .../WiredConditionNotHabboCount.java | 23 ++++---- .../conditions/WiredConditionTeamMember.java | 10 ++-- .../WiredConditionInputGuardTest.java | 41 +++++++++++++ 7 files changed, 133 insertions(+), 29 deletions(-) create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionInputGuard.java create mode 100644 Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionInputGuardTest.java 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..9781565d 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 @@ -59,16 +59,14 @@ public class WiredConditionHabboCount extends InteractionWiredCondition { if (wiredData.startsWith("{")) { JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.lowerLimit = data.lowerLimit; - this.upperLimit = data.upperLimit; - this.userSource = data.userSource; + this.applyLimits(data.lowerLimit, data.upperLimit); + this.userSource = WiredConditionInputGuard.normalizeUserSource(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()); + this.applyLimits(Integer.parseInt(data[0].trim()), Integer.parseInt(data[1].trim())); } catch (NumberFormatException ignored) { // malformed legacy data — keep the constructed defaults } @@ -110,14 +108,19 @@ 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]; int[] params = settings.getIntParams(); - this.userSource = (params.length > 2) ? params[2] : WiredSourceUtil.SOURCE_TRIGGER; + this.applyLimits(params[0], params[1]); + this.userSource = (params.length > 2) ? WiredConditionInputGuard.normalizeUserSource(params[2]) : WiredSourceUtil.SOURCE_TRIGGER; return true; } + private void applyLimits(int lowerLimit, int upperLimit) { + int[] limits = WiredConditionInputGuard.normalizeUserCountRange(lowerLimit, upperLimit); + this.lowerLimit = limits[0]; + this.upperLimit = limits[1]; + } + static class JsonData { int lowerLimit; int upperLimit; diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionInputGuard.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionInputGuard.java new file mode 100644 index 00000000..4d9e3df5 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionInputGuard.java @@ -0,0 +1,57 @@ +package com.eu.habbo.habbohotel.items.interactions.wired.conditions; + +import com.eu.habbo.habbohotel.games.GameTeamColors; +import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil; + +public final class WiredConditionInputGuard { + public static final int MAX_USER_COUNT_LIMIT = 1000; + public static final int MAX_TIMER_CYCLES = 24 * 60 * 60 * 2; + + private WiredConditionInputGuard() { + } + + public static GameTeamColors normalizeTeamColor(GameTeamColors value, GameTeamColors fallback) { + return (value != null) ? value : fallback; + } + + public static GameTeamColors normalizeTeamColorType(int value, GameTeamColors fallback) { + for (GameTeamColors color : GameTeamColors.values()) { + if (color.type == value) { + return color; + } + } + + return fallback; + } + + public static int normalizeUserSource(int value) { + return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER; + } + + public static int normalizeTimerCycles(int value) { + if (value < 0) { + return 0; + } + + return Math.min(value, MAX_TIMER_CYCLES); + } + + public static int[] normalizeUserCountRange(int lowerLimit, int upperLimit) { + int lower = clampUserCount(lowerLimit); + int upper = clampUserCount(upperLimit); + + if (lower > upper) { + return new int[]{upper, lower}; + } + + return new int[]{lower, upper}; + } + + private static int clampUserCount(int value) { + if (value < 0) { + return 0; + } + + return Math.min(value, MAX_USER_COUNT_LIMIT); + } +} 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..7d294214 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,10 +52,10 @@ public class WiredConditionLessTimeElapsed extends InteractionWiredCondition { try { if (wiredData.startsWith("{")) { JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.cycles = data.cycles; + this.cycles = WiredConditionInputGuard.normalizeTimerCycles(data.cycles); } else { if (!wiredData.equals("")) - this.cycles = Integer.parseInt(wiredData); + this.cycles = WiredConditionInputGuard.normalizeTimerCycles(Integer.parseInt(wiredData)); } } catch (Exception e) { } @@ -90,7 +90,7 @@ 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 = WiredConditionInputGuard.normalizeTimerCycles(settings.getIntParams()[0]); return true; } 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..865d2af0 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 @@ -52,10 +52,10 @@ public class WiredConditionMoreTimeElapsed extends InteractionWiredCondition { try { if (wiredData.startsWith("{")) { JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.cycles = data.cycles; + this.cycles = WiredConditionInputGuard.normalizeTimerCycles(data.cycles); } else { if (!wiredData.equals("")) - this.cycles = Integer.parseInt(wiredData); + this.cycles = WiredConditionInputGuard.normalizeTimerCycles(Integer.parseInt(wiredData)); } } catch (Exception e) { } @@ -90,7 +90,7 @@ 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 = WiredConditionInputGuard.normalizeTimerCycles(settings.getIntParams()[0]); return true; } 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..f6b6ff2e 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 @@ -59,15 +59,13 @@ public class WiredConditionNotHabboCount extends InteractionWiredCondition { 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; + this.applyLimits(data.lowerLimit, data.upperLimit); + this.userSource = WiredConditionInputGuard.normalizeUserSource(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()); + this.applyLimits(Integer.parseInt(data[0].trim()), Integer.parseInt(data[1].trim())); } catch (NumberFormatException ignored) { // malformed legacy data — keep the constructed defaults } @@ -78,8 +76,8 @@ public class WiredConditionNotHabboCount extends InteractionWiredCondition { @Override public void onPickUp() { - this.upperLimit = 0; - this.lowerLimit = 20; + this.lowerLimit = 10; + this.upperLimit = 20; this.userSource = WiredSourceUtil.SOURCE_TRIGGER; } @@ -109,14 +107,19 @@ 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]; int[] params = settings.getIntParams(); - this.userSource = (params.length > 2) ? params[2] : WiredSourceUtil.SOURCE_TRIGGER; + this.applyLimits(params[0], params[1]); + this.userSource = (params.length > 2) ? WiredConditionInputGuard.normalizeUserSource(params[2]) : WiredSourceUtil.SOURCE_TRIGGER; return true; } + private void applyLimits(int lowerLimit, int upperLimit) { + int[] limits = WiredConditionInputGuard.normalizeUserCountRange(lowerLimit, upperLimit); + this.lowerLimit = limits[0]; + this.upperLimit = limits[1]; + } + static class JsonData { int lowerLimit; int upperLimit; diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionTeamMember.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionTeamMember.java index 4ca7b4e1..7707c680 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionTeamMember.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionTeamMember.java @@ -97,12 +97,12 @@ public class WiredConditionTeamMember extends InteractionWiredCondition { if (wiredData.startsWith("{")) { JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); - this.teamColor = data.teamColor; - this.userSource = data.userSource; + this.teamColor = WiredConditionInputGuard.normalizeTeamColor(data.teamColor, GameTeamColors.RED); + this.userSource = WiredConditionInputGuard.normalizeUserSource(data.userSource); this.quantifier = this.normalizeQuantifier(data.quantifier, QUANTIFIER_ANY); } else { if (!wiredData.equals("")) - this.teamColor = GameTeamColors.values()[Integer.parseInt(wiredData)]; + this.teamColor = WiredConditionInputGuard.normalizeTeamColorType(Integer.parseInt(wiredData), GameTeamColors.RED); this.userSource = WiredSourceUtil.SOURCE_TRIGGER; this.quantifier = QUANTIFIER_ANY; } @@ -147,8 +147,8 @@ public class WiredConditionTeamMember extends InteractionWiredCondition { public boolean saveData(WiredSettings settings) { if(settings.getIntParams().length < 1) return false; int[] params = settings.getIntParams(); - this.teamColor = GameTeamColors.values()[params[0]]; - this.userSource = (params.length > 1) ? params[1] : WiredSourceUtil.SOURCE_TRIGGER; + this.teamColor = WiredConditionInputGuard.normalizeTeamColorType(params[0], GameTeamColors.RED); + this.userSource = (params.length > 1) ? WiredConditionInputGuard.normalizeUserSource(params[1]) : WiredSourceUtil.SOURCE_TRIGGER; this.quantifier = (params.length > 2) ? this.normalizeQuantifier(params[2], QUANTIFIER_ALL) : QUANTIFIER_ANY; return true; diff --git a/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionInputGuardTest.java b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionInputGuardTest.java new file mode 100644 index 00000000..0d9f6747 --- /dev/null +++ b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionInputGuardTest.java @@ -0,0 +1,41 @@ +package com.eu.habbo.habbohotel.items.interactions.wired.conditions; + +import com.eu.habbo.habbohotel.games.GameTeamColors; +import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class WiredConditionInputGuardTest { + + @Test + void teamColorsAreResolvedByProtocolTypeWithoutArrayIndexing() { + assertEquals(GameTeamColors.RED, WiredConditionInputGuard.normalizeTeamColorType(1, GameTeamColors.RED)); + assertEquals(GameTeamColors.TEN, WiredConditionInputGuard.normalizeTeamColorType(14, GameTeamColors.RED)); + assertEquals(GameTeamColors.RED, WiredConditionInputGuard.normalizeTeamColorType(-1, GameTeamColors.RED)); + assertEquals(GameTeamColors.RED, WiredConditionInputGuard.normalizeTeamColorType(Integer.MAX_VALUE, GameTeamColors.RED)); + } + + @Test + void userSourcesFallBackToTriggerWhenUnknown() { + assertEquals(WiredSourceUtil.SOURCE_TRIGGER, WiredConditionInputGuard.normalizeUserSource(-100)); + assertEquals(WiredSourceUtil.SOURCE_SELECTOR, WiredConditionInputGuard.normalizeUserSource(WiredSourceUtil.SOURCE_SELECTOR)); + assertEquals(WiredSourceUtil.SOURCE_SIGNAL, WiredConditionInputGuard.normalizeUserSource(WiredSourceUtil.SOURCE_SIGNAL)); + } + + @Test + void userCountRangesArePositiveOrderedAndCapped() { + assertArrayEquals(new int[]{0, 50}, WiredConditionInputGuard.normalizeUserCountRange(-50, 50)); + assertArrayEquals(new int[]{10, 20}, WiredConditionInputGuard.normalizeUserCountRange(20, 10)); + assertArrayEquals(new int[]{1000, 1000}, WiredConditionInputGuard.normalizeUserCountRange(Integer.MAX_VALUE, Integer.MAX_VALUE)); + } + + @Test + void elapsedTimerCyclesArePositiveAndBounded() { + assertEquals(0, WiredConditionInputGuard.normalizeTimerCycles(-1)); + assertEquals(42, WiredConditionInputGuard.normalizeTimerCycles(42)); + assertEquals(WiredConditionInputGuard.MAX_TIMER_CYCLES, + WiredConditionInputGuard.normalizeTimerCycles(Integer.MAX_VALUE)); + } +}