From dbcf139a52a7d0b5bb3a06bc35945392679cbd33 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Sat, 13 Jun 2026 15:49:35 +0200 Subject: [PATCH] fix(housekeeping): audit sensitive actions Several privileged housekeeping handlers returned success without appending an audit entry, so the action log stayed incomplete even after the log table schema was fixed. Add audit writes for ban, mute, password reset, HC changes, trade lock, item grants, room ownership transfer, and hotel alerts, and cover the expected logging surface with a contract test. --- .../HousekeepingBanUserEvent.java | 5 +++ .../HousekeepingGrantItemEvent.java | 5 +++ .../HousekeepingMuteUserEvent.java | 5 +++ .../HousekeepingResetUserPasswordEvent.java | 5 +++ .../HousekeepingSendHotelAlertEvent.java | 5 +++ .../HousekeepingSetHcSubscriptionEvent.java | 5 +++ .../HousekeepingTradeLockUserEvent.java | 5 +++ ...ousekeepingTransferRoomOwnershipEvent.java | 5 +++ ...HousekeepingAuditCoverageContractTest.java | 33 +++++++++++++++++++ 9 files changed, 73 insertions(+) create mode 100644 Emulator/src/test/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingAuditCoverageContractTest.java diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingBanUserEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingBanUserEvent.java index 1b637fed..9d8faf2f 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingBanUserEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingBanUserEvent.java @@ -61,6 +61,11 @@ public class HousekeepingBanUserEvent extends MessageHandler { // object, so we return the target user id as the actionId — it's // the only stable handle the client can use until a dedicated // housekeeping_log row id supersedes it. + 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 : ""), + this.client.getHabbo().getHabboInfo().getIpLogin()); this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, "")); } } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingGrantItemEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingGrantItemEvent.java index 15ece6ad..77da4407 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingGrantItemEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingGrantItemEvent.java @@ -62,6 +62,11 @@ public class HousekeepingGrantItemEvent extends MessageHandler { return; } + com.eu.habbo.habbohotel.modtool.HousekeepingAuditLog.log( + this.client.getHabbo().getHabboInfo().getId(), + this.client.getHabbo().getHabboInfo().getUsername(), + ACTION_KEY, userId, "itemId=" + itemId + " quantity=" + quantity, + this.client.getHabbo().getHabboInfo().getIpLogin()); this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, "")); } } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingMuteUserEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingMuteUserEvent.java index 4b35c838..68f4d346 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingMuteUserEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingMuteUserEvent.java @@ -55,6 +55,11 @@ public class HousekeepingMuteUserEvent extends MessageHandler { 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 : ""), + this.client.getHabbo().getHabboInfo().getIpLogin()); this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, "")); } } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingResetUserPasswordEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingResetUserPasswordEvent.java index 87fe3e5a..87cf140b 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingResetUserPasswordEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingResetUserPasswordEvent.java @@ -79,6 +79,11 @@ public class HousekeepingResetUserPasswordEvent extends MessageHandler { // Plaintext flows through `message` — the client surfaces it via the // status banner so the operator can read it once. SSL is on the // operator: the only secure transport for the WS is wss://. + com.eu.habbo.habbohotel.modtool.HousekeepingAuditLog.log( + this.client.getHabbo().getHabboInfo().getId(), + this.client.getHabbo().getHabboInfo().getUsername(), + ACTION_KEY, userId, "password_reset=1", + this.client.getHabbo().getHabboInfo().getIpLogin()); this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, plain)); } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingSendHotelAlertEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingSendHotelAlertEvent.java index e3a83daa..0f397c35 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingSendHotelAlertEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingSendHotelAlertEvent.java @@ -53,6 +53,11 @@ public class HousekeepingSendHotelAlertEvent extends MessageHandler { reached++; } + com.eu.habbo.habbohotel.modtool.HousekeepingAuditLog.log( + this.client.getHabbo().getHabboInfo().getId(), + this.client.getHabbo().getHabboInfo().getUsername(), + ACTION_KEY, 0, "reached=" + reached + " message=" + message, + this.client.getHabbo().getHabboInfo().getIpLogin()); this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, reached, "")); } } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingSetHcSubscriptionEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingSetHcSubscriptionEvent.java index 508c2a7c..7d9f13de 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingSetHcSubscriptionEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingSetHcSubscriptionEvent.java @@ -76,6 +76,11 @@ public class HousekeepingSetHcSubscriptionEvent extends MessageHandler { return; } + com.eu.habbo.habbohotel.modtool.HousekeepingAuditLog.log( + this.client.getHabbo().getHabboInfo().getId(), + this.client.getHabbo().getHabboInfo().getUsername(), + ACTION_KEY, userId, "days=" + days + " expire=" + newExpire, + this.client.getHabbo().getHabboInfo().getIpLogin()); this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, "")); } } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingTradeLockUserEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingTradeLockUserEvent.java index 2c0a5669..5547da07 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingTradeLockUserEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingTradeLockUserEvent.java @@ -77,6 +77,11 @@ 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 : ""), + this.client.getHabbo().getHabboInfo().getIpLogin()); this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, "")); } } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingTransferRoomOwnershipEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingTransferRoomOwnershipEvent.java index 70c6bf80..eba00fb2 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingTransferRoomOwnershipEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingTransferRoomOwnershipEvent.java @@ -62,6 +62,11 @@ public class HousekeepingTransferRoomOwnershipEvent extends MessageHandler { return; } + com.eu.habbo.habbohotel.modtool.HousekeepingAuditLog.log( + this.client.getHabbo().getHabboInfo().getId(), + this.client.getHabbo().getHabboInfo().getUsername(), + ACTION_KEY, newOwnerId, "roomId=" + roomId + " newOwner=" + newOwner.getUsername(), + this.client.getHabbo().getHabboInfo().getIpLogin()); this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, roomId, "")); } } diff --git a/Emulator/src/test/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingAuditCoverageContractTest.java b/Emulator/src/test/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingAuditCoverageContractTest.java new file mode 100644 index 00000000..01981c7a --- /dev/null +++ b/Emulator/src/test/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingAuditCoverageContractTest.java @@ -0,0 +1,33 @@ +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 HousekeepingAuditCoverageContractTest { + private static final List SENSITIVE_HANDLERS = List.of( + "HousekeepingBanUserEvent.java", + "HousekeepingMuteUserEvent.java", + "HousekeepingResetUserPasswordEvent.java", + "HousekeepingSetHcSubscriptionEvent.java", + "HousekeepingTradeLockUserEvent.java", + "HousekeepingGrantItemEvent.java", + "HousekeepingTransferRoomOwnershipEvent.java", + "HousekeepingSendHotelAlertEvent.java" + ); + + @Test + void sensitiveHousekeepingActionsWriteAuditEntries() throws Exception { + Path base = Path.of("src/main/java/com/eu/habbo/messages/incoming/housekeeping"); + + for (String handler : SENSITIVE_HANDLERS) { + String source = Files.readString(base.resolve(handler)); + assertTrue(source.contains("HousekeepingAuditLog.log"), + handler + " must append a housekeeping audit log entry after successful privileged actions"); + } + } +}