diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/modtool/ModToolManager.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/modtool/ModToolManager.java index 0f59478d..9883ec7a 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/modtool/ModToolManager.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/modtool/ModToolManager.java @@ -410,13 +410,16 @@ public class ModToolManager { return; } + if (target == null || !canModerateTarget(moderator, target.getHabboInfo().getId())) { + return; + } + SupportUserAlertedEvent alertedEvent = new SupportUserAlertedEvent(moderator, target, message, reason); if (Emulator.getPluginManager().fireEvent(alertedEvent).isCancelled()) return; - if (target != null) - alertedEvent.target.getClient().sendResponse(new ModToolIssueHandledComposer(alertedEvent.message)); + alertedEvent.target.getClient().sendResponse(new ModToolIssueHandledComposer(alertedEvent.message)); } public void kick(Habbo moderator, Habbo target, String message) { @@ -490,6 +493,17 @@ public class ModToolManager { return bans; } + public static boolean canModerateTarget(Habbo moderator, int targetUserId) { + if (moderator == null || targetUserId <= 0) + return false; + + HabboInfo targetInfo = Emulator.getGameEnvironment().getHabboManager().getHabboInfo(targetUserId); + if (targetInfo == null) + return false; + + return targetInfo.getRank().getId() < moderator.getHabboInfo().getRank().getId(); + } + public void roomAction(Room room, Habbo moderator, boolean kickUsers, boolean lockDoor, boolean changeTitle) { SupportRoomActionEvent roomActionEvent = new SupportRoomActionEvent(moderator, room, kickUsers, lockDoor, changeTitle); Emulator.getPluginManager().fireEvent(roomActionEvent); diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolIssueDefaultSanctionEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolIssueDefaultSanctionEvent.java index 48beb3c7..b237c5f5 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolIssueDefaultSanctionEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolIssueDefaultSanctionEvent.java @@ -30,6 +30,10 @@ public class ModToolIssueDefaultSanctionEvent extends MessageHandler { if (defaultSanction != null) { Habbo target = Emulator.getGameEnvironment().getHabboManager().getHabbo(issue.reportedId); + if (!ModToolManager.canModerateTarget(this.client.getHabbo(), issue.reportedId)) { + return; + } + if (defaultSanction.banLength > 0) { Emulator.getGameEnvironment().getModToolManager().ban(issue.reportedId, this.client.getHabbo(), defaultSanction.message, defaultSanction.banLength * 86400, ModToolBanType.ACCOUNT, modToolCategory.id); } else if (defaultSanction.muteLength > 0) { diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolKickEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolKickEvent.java index 77370b36..6491a4bf 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolKickEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolKickEvent.java @@ -1,6 +1,8 @@ package com.eu.habbo.messages.incoming.modtool; import com.eu.habbo.Emulator; +import com.eu.habbo.habbohotel.modtool.ScripterManager; +import com.eu.habbo.habbohotel.permissions.Permission; import com.eu.habbo.messages.incoming.MessageHandler; public class ModToolKickEvent extends MessageHandler { @@ -11,6 +13,11 @@ public class ModToolKickEvent extends MessageHandler { @Override public void handle() throws Exception { + if (!this.client.getHabbo().hasPermission(Permission.ACC_SUPPORTTOOL)) { + ScripterManager.scripterDetected(this.client, Emulator.getTexts().getValue("scripter.warning.modtools.kick").replace("%username%", this.client.getHabbo().getHabboInfo().getUsername())); + return; + } + Emulator.getGameEnvironment().getModToolManager().kick(this.client.getHabbo(), Emulator.getGameEnvironment().getHabboManager().getHabbo(this.packet.readInt()), this.packet.readString()); } } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionAlertEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionAlertEvent.java index 21bd1393..cb609001 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionAlertEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionAlertEvent.java @@ -28,6 +28,10 @@ public class ModToolSanctionAlertEvent extends MessageHandler { Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId); if (habbo != null) { + if (!ModToolManager.canModerateTarget(this.client.getHabbo(), userId)) { + return; + } + ModToolSanctions modToolSanctions = Emulator.getGameEnvironment().getModToolSanctions(); if (Emulator.getConfig().getBoolean("hotel.sanctions.enabled")) { @@ -55,4 +59,4 @@ public class ModToolSanctionAlertEvent extends MessageHandler { } } } -} \ No newline at end of file +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionMuteEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionMuteEvent.java index 3be70cf6..16a2bbdd 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionMuteEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionMuteEvent.java @@ -30,6 +30,10 @@ public class ModToolSanctionMuteEvent extends MessageHandler { Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId); if (habbo != null) { + if (!ModToolManager.canModerateTarget(this.client.getHabbo(), userId)) { + return; + } + ModToolSanctions modToolSanctions = Emulator.getGameEnvironment().getModToolSanctions(); if (Emulator.getConfig().getBoolean("hotel.sanctions.enabled")) { @@ -67,4 +71,4 @@ public class ModToolSanctionMuteEvent extends MessageHandler { } } } -} \ No newline at end of file +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionTradeLockEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionTradeLockEvent.java index d501eba5..9f666868 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionTradeLockEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionTradeLockEvent.java @@ -29,6 +29,10 @@ public class ModToolSanctionTradeLockEvent extends MessageHandler { Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId); if (habbo != null) { + if (!ModToolManager.canModerateTarget(this.client.getHabbo(), userId)) { + return; + } + ModToolSanctions modToolSanctions = Emulator.getGameEnvironment().getModToolSanctions(); if (Emulator.getConfig().getBoolean("hotel.sanctions.enabled")) { @@ -57,4 +61,4 @@ public class ModToolSanctionTradeLockEvent extends MessageHandler { } } } -} \ No newline at end of file +} diff --git a/Emulator/src/test/java/com/eu/habbo/messages/incoming/modtool/ModToolPermissionContractTest.java b/Emulator/src/test/java/com/eu/habbo/messages/incoming/modtool/ModToolPermissionContractTest.java new file mode 100644 index 00000000..460da889 --- /dev/null +++ b/Emulator/src/test/java/com/eu/habbo/messages/incoming/modtool/ModToolPermissionContractTest.java @@ -0,0 +1,65 @@ +package com.eu.habbo.messages.incoming.modtool; + +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 ModToolPermissionContractTest { + private static final List STAFF_ONLY_HANDLERS = List.of( + "ModToolAlertEvent.java", + "ModToolChangeRoomSettingsEvent.java", + "ModToolCloseTicketEvent.java", + "ModToolIssueChangeTopicEvent.java", + "ModToolIssueDefaultSanctionEvent.java", + "ModToolKickEvent.java", + "ModToolPickTicketEvent.java", + "ModToolReleaseTicketEvent.java", + "ModToolRequestIssueChatlogEvent.java", + "ModToolRequestRoomChatlogEvent.java", + "ModToolRequestRoomInfoEvent.java", + "ModToolRequestRoomUserChatlogEvent.java", + "ModToolRequestRoomVisitsEvent.java", + "ModToolRequestUserChatlogEvent.java", + "ModToolRequestUserInfoEvent.java", + "ModToolRoomAlertEvent.java", + "ModToolSanctionAlertEvent.java", + "ModToolSanctionBanEvent.java", + "ModToolSanctionMuteEvent.java", + "ModToolSanctionTradeLockEvent.java", + "ModToolWarnEvent.java" + ); + + @Test + void staffOnlyModToolHandlersRequireSupportToolPermission() throws Exception { + Path base = Path.of("src/main/java/com/eu/habbo/messages/incoming/modtool"); + + for (String handler : STAFF_ONLY_HANDLERS) { + String source = Files.readString(base.resolve(handler)); + assertTrue(source.contains("hasPermission(Permission.ACC_SUPPORTTOOL)"), + handler + " must require ACC_SUPPORTTOOL before exposing moderator actions or private logs"); + } + } + + @Test + void modToolSanctionsCannotTargetSameOrHigherRanks() throws Exception { + Path base = Path.of("src/main/java/com/eu/habbo/messages/incoming/modtool"); + + for (String handler : List.of( + "ModToolSanctionAlertEvent.java", + "ModToolSanctionMuteEvent.java", + "ModToolSanctionTradeLockEvent.java", + "ModToolIssueDefaultSanctionEvent.java")) { + String source = Files.readString(base.resolve(handler)); + assertTrue(source.contains("ModToolManager.canModerateTarget"), + handler + " must enforce the modtool target rank ceiling before applying sanctions"); + } + + String manager = Files.readString(Path.of("src/main/java/com/eu/habbo/habbohotel/modtool/ModToolManager.java")); + assertTrue(manager.contains("!canModerateTarget(moderator, target.getHabboInfo().getId())"), + "ModToolManager.alert must refuse alerts/warnings against same-or-higher-rank targets"); + } +}