Merge pull request #225 from simoleo89/fix/user-profile-inputs

fix(users): bound profile setting inputs
This commit is contained in:
DuckieTM
2026-06-17 09:58:55 +02:00
committed by GitHub
8 changed files with 114 additions and 11 deletions
@@ -10,6 +10,10 @@ public class RequestProfileFriendsEvent extends MessageHandler {
@Override @Override
public void handle() throws Exception { public void handle() throws Exception {
int userId = this.packet.readInt(); int userId = this.packet.readInt();
if (!UserInputGuard.isPositiveId(userId))
return;
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId); Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId);
if (habbo != null) if (habbo != null)
@@ -10,6 +10,10 @@ public class RequestUserProfileEvent extends MessageHandler {
@Override @Override
public void handle() throws Exception { public void handle() throws Exception {
int habboId = this.packet.readInt(); int habboId = this.packet.readInt();
if (!UserInputGuard.isPositiveId(habboId))
return;
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(habboId); Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(habboId);
if (habbo != null) if (habbo != null)
@@ -10,6 +10,10 @@ public class RequestWearingBadgesEvent extends MessageHandler {
@Override @Override
public void handle() throws Exception { public void handle() throws Exception {
int userId = this.packet.readInt(); int userId = this.packet.readInt();
if (!UserInputGuard.isPositiveId(userId))
return;
Habbo habbo = Emulator.getGameServer().getGameClientManager().getHabbo(userId); Habbo habbo = Emulator.getGameServer().getGameClientManager().getHabbo(userId);
if (habbo == null || habbo.getHabboInfo() == null || habbo.getInventory() == null || habbo.getInventory().getBadgesComponent() == null) if (habbo == null || habbo.getHabboInfo() == null || habbo.getInventory() == null || habbo.getInventory().getBadgesComponent() == null)
@@ -9,15 +9,16 @@ import com.eu.habbo.plugin.events.users.UserSavedMottoEvent;
public class SaveMottoEvent extends MessageHandler { public class SaveMottoEvent extends MessageHandler {
@Override @Override
public void handle() throws Exception { public void handle() throws Exception {
String motto = Emulator.getGameEnvironment().getWordFilter().filter(this.packet.readString(), this.client.getHabbo()); String motto = UserInputGuard.normalizeText(Emulator.getGameEnvironment().getWordFilter().filter(this.packet.readString(), this.client.getHabbo()));
UserSavedMottoEvent event = new UserSavedMottoEvent(this.client.getHabbo(), this.client.getHabbo().getHabboInfo().getMotto(), motto); UserSavedMottoEvent event = new UserSavedMottoEvent(this.client.getHabbo(), this.client.getHabbo().getHabboInfo().getMotto(), motto);
Emulator.getPluginManager().fireEvent(event); Emulator.getPluginManager().fireEvent(event);
motto = event.newMotto; motto = UserInputGuard.normalizeText(event.newMotto);
if(motto.length() <= Emulator.getConfig().getInt("motto.max_length", 38)) { if (motto.length() > Emulator.getConfig().getInt("motto.max_length", 38))
this.client.getHabbo().getHabboInfo().setMotto(motto); return;
this.client.getHabbo().getHabboInfo().run();
} this.client.getHabbo().getHabboInfo().setMotto(motto);
this.client.getHabbo().getHabboInfo().run();
if (this.client.getHabbo().getHabboInfo().getCurrentRoom() != null) { if (this.client.getHabbo().getHabboInfo().getCurrentRoom() != null) {
this.client.getHabbo().getHabboInfo().getCurrentRoom().sendComposer(new RoomUserDataComposer(this.client.getHabbo()).compose()); this.client.getHabbo().getHabboInfo().getCurrentRoom().sendComposer(new RoomUserDataComposer(this.client.getHabbo()).compose());
@@ -7,9 +7,9 @@ import com.eu.habbo.plugin.events.users.UserSavedSettingsEvent;
public class SaveUserVolumesEvent extends MessageHandler { public class SaveUserVolumesEvent extends MessageHandler {
@Override @Override
public void handle() throws Exception { public void handle() throws Exception {
int system = this.packet.readInt(); int system = UserInputGuard.clampVolume(this.packet.readInt());
int furni = this.packet.readInt(); int furni = UserInputGuard.clampVolume(this.packet.readInt());
int trax = this.packet.readInt(); int trax = UserInputGuard.clampVolume(this.packet.readInt());
this.client.getHabbo().getHabboStats().volumeSystem = system; this.client.getHabbo().getHabboStats().volumeSystem = system;
this.client.getHabbo().getHabboStats().volumeFurni = furni; this.client.getHabbo().getHabboStats().volumeFurni = furni;
@@ -5,7 +5,7 @@ import com.eu.habbo.messages.incoming.MessageHandler;
public class UpdateUIFlagsEvent extends MessageHandler { public class UpdateUIFlagsEvent extends MessageHandler {
@Override @Override
public void handle() throws Exception { public void handle() throws Exception {
int flags = this.packet.readInt(); int flags = UserInputGuard.sanitizeUiFlags(this.packet.readInt());
this.client.getHabbo().getHabboStats().uiFlags = flags; this.client.getHabbo().getHabboStats().uiFlags = flags;
this.client.getHabbo().getHabboStats().run(); this.client.getHabbo().getHabboStats().run();
@@ -0,0 +1,26 @@
package com.eu.habbo.messages.incoming.users;
final class UserInputGuard {
static final int MIN_VOLUME = 0;
static final int MAX_VOLUME = 100;
static final int MAX_UI_FLAGS = 0xFFFF;
private UserInputGuard() {
}
static boolean isPositiveId(int id) {
return id > 0;
}
static int clampVolume(int volume) {
return Math.max(MIN_VOLUME, Math.min(MAX_VOLUME, volume));
}
static int sanitizeUiFlags(int flags) {
return flags < 0 ? 0 : flags & MAX_UI_FLAGS;
}
static String normalizeText(String value) {
return value == null ? "" : value.trim();
}
}
@@ -0,0 +1,64 @@
package com.eu.habbo.messages.incoming.users;
import org.junit.jupiter.api.Test;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class UserInputGuardContractTest {
private static String source(String name) throws Exception {
return Files.readString(Path.of("src/main/java/com/eu/habbo/messages/incoming/users/" + name + ".java"));
}
@Test
void userProfileLookupsRejectInvalidIdsBeforeOfflineQueries() throws Exception {
for (String handler : new String[]{"RequestUserProfileEvent", "RequestProfileFriendsEvent", "RequestWearingBadgesEvent"}) {
String source = source(handler);
int read = source.indexOf("this.packet.readInt()");
int guard = source.indexOf("UserInputGuard.isPositiveId", read);
int lookup = Math.max(source.indexOf("getOfflineHabboInfo", guard), source.indexOf("getBadgesOfflineHabbo", guard));
assertTrue(guard > read, handler + " should validate the packet id after reading it");
assertTrue(lookup == -1 || guard < lookup, handler + " should validate ids before offline lookups");
}
}
@Test
void settingsInputsAreNormalizedBeforePersistence() throws Exception {
String volumes = source("SaveUserVolumesEvent");
String flags = source("UpdateUIFlagsEvent");
assertTrue(volumes.contains("UserInputGuard.clampVolume(this.packet.readInt())"),
"volume settings should be clamped to the client-supported range");
assertTrue(flags.contains("UserInputGuard.sanitizeUiFlags(this.packet.readInt())"),
"UI flags should be sanitized before persistence");
}
@Test
void mottoIsNormalizedAndRejectedBeforeSaveSideEffects() throws Exception {
String motto = source("SaveMottoEvent");
int pluginValue = motto.indexOf("UserInputGuard.normalizeText(event.newMotto)");
int lengthGuard = motto.indexOf("motto.length() > Emulator.getConfig().getInt", pluginValue);
int save = motto.indexOf("setMotto(motto)", lengthGuard);
int achievement = motto.indexOf("AchievementManager.progressAchievement", save);
assertTrue(pluginValue > -1, "plugin-mutated motto should be normalized");
assertTrue(lengthGuard > pluginValue && lengthGuard < save,
"motto length should be validated before saving");
assertTrue(save < achievement,
"motto achievement should only progress after a valid save");
}
@Test
void helperClampsAndMasksValues() {
assertEquals(0, UserInputGuard.clampVolume(-20));
assertEquals(40, UserInputGuard.clampVolume(40));
assertEquals(100, UserInputGuard.clampVolume(101));
assertEquals(0, UserInputGuard.sanitizeUiFlags(-1));
assertEquals(0xFFFF, UserInputGuard.sanitizeUiFlags(0x1FFFF));
}
}