You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-19 15:06:19 +00:00
fix(housekeeping): bound staff supplied text
This commit is contained in:
+4
-4
@@ -30,10 +30,10 @@ public class HousekeepingBanUserEvent extends MessageHandler {
|
||||
}
|
||||
|
||||
int userId = this.packet.readInt();
|
||||
String reason = this.packet.readString();
|
||||
String reason = HousekeepingInputGuard.normalize(this.packet.readString());
|
||||
int hours = this.packet.readInt();
|
||||
|
||||
if (userId <= 0 || hours <= 0) {
|
||||
if (userId <= 0 || hours <= 0 || !HousekeepingInputGuard.isWithinLimit(reason, HousekeepingInputGuard.MAX_REASON_LENGTH)) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.invalid_input"));
|
||||
return;
|
||||
}
|
||||
@@ -46,7 +46,7 @@ public class HousekeepingBanUserEvent extends MessageHandler {
|
||||
int duration = HousekeepingSanctionDuration.secondsFromHours(hours);
|
||||
|
||||
List<ModToolBan> bans = Emulator.getGameEnvironment().getModToolManager()
|
||||
.ban(userId, this.client.getHabbo(), reason != null ? reason : "", duration, ModToolBanType.ACCOUNT, 0);
|
||||
.ban(userId, this.client.getHabbo(), reason, duration, ModToolBanType.ACCOUNT, 0);
|
||||
|
||||
if (bans == null || bans.isEmpty()) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.ban_failed"));
|
||||
@@ -60,7 +60,7 @@ public class HousekeepingBanUserEvent extends MessageHandler {
|
||||
com.eu.habbo.habbohotel.modtool.HousekeepingAuditLog.log(
|
||||
this.client.getHabbo().getHabboInfo().getId(),
|
||||
this.client.getHabbo().getHabboInfo().getUsername(),
|
||||
ACTION_KEY, userId, "hours=" + hours + " reason=" + (reason != null ? reason : ""),
|
||||
ACTION_KEY, userId, "hours=" + hours + " reason=" + HousekeepingInputGuard.auditValue(reason),
|
||||
this.client.getHabbo().getHabboInfo().getIpLogin());
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, ""));
|
||||
}
|
||||
|
||||
+2
-2
@@ -20,9 +20,9 @@ public class HousekeepingFindUserByNameEvent extends MessageHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
String username = this.packet.readString();
|
||||
String username = HousekeepingInputGuard.normalize(this.packet.readString());
|
||||
|
||||
if (username == null || username.isEmpty()) {
|
||||
if (username.isEmpty() || !HousekeepingInputGuard.isWithinLimit(username, HousekeepingInputGuard.MAX_LOOKUP_LENGTH)) {
|
||||
this.client.sendResponse(new HousekeepingUserDetailComposer(null));
|
||||
return;
|
||||
}
|
||||
|
||||
+4
-4
@@ -26,9 +26,9 @@ public class HousekeepingForceDisconnectUserEvent extends MessageHandler {
|
||||
}
|
||||
|
||||
int userId = this.packet.readInt();
|
||||
String reason = this.packet.readString();
|
||||
String reason = HousekeepingInputGuard.normalize(this.packet.readString());
|
||||
|
||||
if (userId <= 0) {
|
||||
if (userId <= 0 || !HousekeepingInputGuard.isWithinLimit(reason, HousekeepingInputGuard.MAX_REASON_LENGTH)) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.invalid_input"));
|
||||
return;
|
||||
}
|
||||
@@ -45,7 +45,7 @@ public class HousekeepingForceDisconnectUserEvent extends MessageHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
if (reason != null && !reason.isEmpty()) {
|
||||
if (!reason.isEmpty()) {
|
||||
target.alert(reason);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public class HousekeepingForceDisconnectUserEvent extends MessageHandler {
|
||||
com.eu.habbo.habbohotel.modtool.HousekeepingAuditLog.log(
|
||||
this.client.getHabbo().getHabboInfo().getId(),
|
||||
this.client.getHabbo().getHabboInfo().getUsername(),
|
||||
ACTION_KEY, userId, "reason=" + (reason != null ? reason : ""),
|
||||
ACTION_KEY, userId, "reason=" + HousekeepingInputGuard.auditValue(reason),
|
||||
this.client.getHabbo().getHabboInfo().getIpLogin());
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, ""));
|
||||
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.eu.habbo.messages.incoming.housekeeping;
|
||||
|
||||
final class HousekeepingInputGuard {
|
||||
static final int MAX_LOOKUP_LENGTH = 64;
|
||||
static final int MAX_REASON_LENGTH = 500;
|
||||
static final int MAX_ALERT_LENGTH = 1000;
|
||||
|
||||
private HousekeepingInputGuard() {
|
||||
}
|
||||
|
||||
static String normalize(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
static boolean isWithinLimit(String value, int maxLength) {
|
||||
return value != null && value.length() <= maxLength;
|
||||
}
|
||||
|
||||
static String auditValue(String value) {
|
||||
String normalized = normalize(value)
|
||||
.replace('\r', ' ')
|
||||
.replace('\n', ' ')
|
||||
.replace('\t', ' ');
|
||||
|
||||
return normalized.length() > MAX_REASON_LENGTH ? normalized.substring(0, MAX_REASON_LENGTH) : normalized;
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -28,9 +28,9 @@ public class HousekeepingKickUserEvent extends MessageHandler {
|
||||
}
|
||||
|
||||
int userId = this.packet.readInt();
|
||||
String reason = this.packet.readString();
|
||||
String reason = HousekeepingInputGuard.normalize(this.packet.readString());
|
||||
|
||||
if (userId <= 0) {
|
||||
if (userId <= 0 || !HousekeepingInputGuard.isWithinLimit(reason, HousekeepingInputGuard.MAX_REASON_LENGTH)) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.invalid_input"));
|
||||
return;
|
||||
}
|
||||
@@ -56,14 +56,14 @@ public class HousekeepingKickUserEvent extends MessageHandler {
|
||||
Emulator.getGameEnvironment().getRoomManager().leaveRoom(target, target.getHabboInfo().getCurrentRoom());
|
||||
}
|
||||
|
||||
if (reason != null && !reason.isEmpty()) {
|
||||
if (!reason.isEmpty()) {
|
||||
target.alert(reason);
|
||||
}
|
||||
|
||||
com.eu.habbo.habbohotel.modtool.HousekeepingAuditLog.log(
|
||||
this.client.getHabbo().getHabboInfo().getId(),
|
||||
this.client.getHabbo().getHabboInfo().getUsername(),
|
||||
ACTION_KEY, userId, "reason=" + (reason != null ? reason : ""),
|
||||
ACTION_KEY, userId, "reason=" + HousekeepingInputGuard.auditValue(reason),
|
||||
this.client.getHabbo().getHabboInfo().getIpLogin());
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, ""));
|
||||
}
|
||||
|
||||
+4
-4
@@ -28,10 +28,10 @@ public class HousekeepingMuteUserEvent extends MessageHandler {
|
||||
}
|
||||
|
||||
int userId = this.packet.readInt();
|
||||
String reason = this.packet.readString();
|
||||
String reason = HousekeepingInputGuard.normalize(this.packet.readString());
|
||||
int minutes = this.packet.readInt();
|
||||
|
||||
if (userId <= 0 || minutes <= 0) {
|
||||
if (userId <= 0 || minutes <= 0 || !HousekeepingInputGuard.isWithinLimit(reason, HousekeepingInputGuard.MAX_REASON_LENGTH)) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.invalid_input"));
|
||||
return;
|
||||
}
|
||||
@@ -50,14 +50,14 @@ public class HousekeepingMuteUserEvent extends MessageHandler {
|
||||
|
||||
target.mute(HousekeepingSanctionDuration.secondsFromMinutes(minutes), false);
|
||||
|
||||
if (reason != null && !reason.isEmpty()) {
|
||||
if (!reason.isEmpty()) {
|
||||
target.alert(reason);
|
||||
}
|
||||
|
||||
com.eu.habbo.habbohotel.modtool.HousekeepingAuditLog.log(
|
||||
this.client.getHabbo().getHabboInfo().getId(),
|
||||
this.client.getHabbo().getHabboInfo().getUsername(),
|
||||
ACTION_KEY, userId, "minutes=" + minutes + " reason=" + (reason != null ? reason : ""),
|
||||
ACTION_KEY, userId, "minutes=" + minutes + " reason=" + HousekeepingInputGuard.auditValue(reason),
|
||||
this.client.getHabbo().getHabboInfo().getIpLogin());
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, ""));
|
||||
}
|
||||
|
||||
+2
-5
@@ -36,14 +36,11 @@ public class HousekeepingSearchRoomsEvent extends MessageHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
String query = this.packet.readString();
|
||||
String query = HousekeepingInputGuard.normalize(this.packet.readString());
|
||||
boolean exactMatch = this.packet.readBoolean();
|
||||
int limit = Math.min(Math.max(this.packet.readInt(), 1), HARD_LIMIT);
|
||||
|
||||
if (query == null) query = "";
|
||||
query = query.trim();
|
||||
|
||||
if (query.isEmpty()) {
|
||||
if (query.isEmpty() || !HousekeepingInputGuard.isWithinLimit(query, HousekeepingInputGuard.MAX_LOOKUP_LENGTH)) {
|
||||
this.client.sendResponse(new HousekeepingRoomListComposer(new ArrayList<>()));
|
||||
return;
|
||||
}
|
||||
|
||||
+8
-3
@@ -31,13 +31,18 @@ public class HousekeepingSendHotelAlertEvent extends MessageHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
String message = this.packet.readString();
|
||||
String message = HousekeepingInputGuard.normalize(this.packet.readString());
|
||||
|
||||
if (message == null || message.trim().isEmpty()) {
|
||||
if (message.isEmpty()) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.alert_empty"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HousekeepingInputGuard.isWithinLimit(message, HousekeepingInputGuard.MAX_ALERT_LENGTH)) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.input_too_long"));
|
||||
return;
|
||||
}
|
||||
|
||||
String body = message + "\r\n-" + this.client.getHabbo().getHabboInfo().getUsername();
|
||||
ServerMessage broadcast = new StaffAlertWithLinkComposer(body, "").compose();
|
||||
|
||||
@@ -56,7 +61,7 @@ public class HousekeepingSendHotelAlertEvent extends MessageHandler {
|
||||
com.eu.habbo.habbohotel.modtool.HousekeepingAuditLog.log(
|
||||
this.client.getHabbo().getHabboInfo().getId(),
|
||||
this.client.getHabbo().getHabboInfo().getUsername(),
|
||||
ACTION_KEY, 0, "reached=" + reached + " message=" + message,
|
||||
ACTION_KEY, 0, "reached=" + reached + " message=" + HousekeepingInputGuard.auditValue(message),
|
||||
this.client.getHabbo().getHabboInfo().getIpLogin());
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, reached, ""));
|
||||
}
|
||||
|
||||
+4
-4
@@ -34,9 +34,9 @@ public class HousekeepingTradeLockUserEvent extends MessageHandler {
|
||||
|
||||
int userId = this.packet.readInt();
|
||||
int hours = this.packet.readInt();
|
||||
String reason = this.packet.readString();
|
||||
String reason = HousekeepingInputGuard.normalize(this.packet.readString());
|
||||
|
||||
if (userId <= 0 || hours <= 0) {
|
||||
if (userId <= 0 || hours <= 0 || !HousekeepingInputGuard.isWithinLimit(reason, HousekeepingInputGuard.MAX_REASON_LENGTH)) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.invalid_input"));
|
||||
return;
|
||||
}
|
||||
@@ -69,7 +69,7 @@ public class HousekeepingTradeLockUserEvent extends MessageHandler {
|
||||
if (online != null) {
|
||||
online.getHabboStats().setAllowTrade(false);
|
||||
|
||||
if (reason != null && !reason.isEmpty()) {
|
||||
if (!reason.isEmpty()) {
|
||||
online.alert(reason);
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ public class HousekeepingTradeLockUserEvent extends MessageHandler {
|
||||
com.eu.habbo.habbohotel.modtool.HousekeepingAuditLog.log(
|
||||
this.client.getHabbo().getHabboInfo().getId(),
|
||||
this.client.getHabbo().getHabboInfo().getUsername(),
|
||||
ACTION_KEY, userId, "hours=" + hours + " lockedUntil=" + lockedUntil + " reason=" + (reason != null ? reason : ""),
|
||||
ACTION_KEY, userId, "hours=" + hours + " lockedUntil=" + lockedUntil + " reason=" + HousekeepingInputGuard.auditValue(reason),
|
||||
this.client.getHabbo().getHabboInfo().getIpLogin());
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, ""));
|
||||
}
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package com.eu.habbo.messages.incoming.housekeeping;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class HousekeepingInputGuardContractTest {
|
||||
@Test
|
||||
void stringDrivenHousekeepingHandlersUseSharedLimits() throws Exception {
|
||||
Path base = Path.of("src/main/java/com/eu/habbo/messages/incoming/housekeeping");
|
||||
|
||||
for (String handler : List.of(
|
||||
"HousekeepingBanUserEvent.java",
|
||||
"HousekeepingForceDisconnectUserEvent.java",
|
||||
"HousekeepingKickUserEvent.java",
|
||||
"HousekeepingMuteUserEvent.java",
|
||||
"HousekeepingTradeLockUserEvent.java",
|
||||
"HousekeepingSendHotelAlertEvent.java",
|
||||
"HousekeepingSearchRoomsEvent.java",
|
||||
"HousekeepingFindUserByNameEvent.java"
|
||||
)) {
|
||||
String source = Files.readString(base.resolve(handler));
|
||||
|
||||
assertTrue(source.contains("HousekeepingInputGuard.normalize"),
|
||||
handler + " must normalize client-provided strings before use");
|
||||
assertTrue(source.contains("HousekeepingInputGuard.isWithinLimit"),
|
||||
handler + " must bound client-provided strings before expensive work or broadcast");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void auditedFreeTextIsSanitizedBeforePersistence() throws Exception {
|
||||
Path base = Path.of("src/main/java/com/eu/habbo/messages/incoming/housekeeping");
|
||||
|
||||
for (String handler : List.of(
|
||||
"HousekeepingBanUserEvent.java",
|
||||
"HousekeepingForceDisconnectUserEvent.java",
|
||||
"HousekeepingKickUserEvent.java",
|
||||
"HousekeepingMuteUserEvent.java",
|
||||
"HousekeepingTradeLockUserEvent.java",
|
||||
"HousekeepingSendHotelAlertEvent.java"
|
||||
)) {
|
||||
String source = Files.readString(base.resolve(handler));
|
||||
|
||||
assertTrue(source.contains("HousekeepingInputGuard.auditValue"),
|
||||
handler + " must collapse control whitespace before writing free text to audit detail");
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.eu.habbo.messages.incoming.housekeeping;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class HousekeepingInputGuardTest {
|
||||
@Test
|
||||
void normalizesNullableText() {
|
||||
assertEquals("", HousekeepingInputGuard.normalize(null));
|
||||
assertEquals("hello", HousekeepingInputGuard.normalize(" hello "));
|
||||
}
|
||||
|
||||
@Test
|
||||
void enforcesInclusiveLengthLimits() {
|
||||
assertTrue(HousekeepingInputGuard.isWithinLimit("abc", 3));
|
||||
assertFalse(HousekeepingInputGuard.isWithinLimit("abcd", 3));
|
||||
assertFalse(HousekeepingInputGuard.isWithinLimit(null, 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
void auditValuesCollapseControlWhitespaceAndCapLength() {
|
||||
String value = HousekeepingInputGuard.auditValue(" one\r\ntwo\tthree ");
|
||||
|
||||
assertEquals("one two three", value);
|
||||
|
||||
String oversized = "x".repeat(HousekeepingInputGuard.MAX_REASON_LENGTH + 1);
|
||||
assertEquals(HousekeepingInputGuard.MAX_REASON_LENGTH, HousekeepingInputGuard.auditValue(oversized).length());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user