diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/guilds/GuildRemoveMemberEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/guilds/GuildRemoveMemberEvent.java index 4b61f258..af303bf3 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/guilds/GuildRemoveMemberEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/guilds/GuildRemoveMemberEvent.java @@ -40,6 +40,19 @@ public class GuildRemoveMemberEvent extends MessageHandler { return; } + GuildMember targetMember = Emulator.getGameEnvironment().getGuildManager().getGuildMember(guildId, userId); + if (targetMember == null) { + return; + } + + boolean actorIsGuildOwner = guild.getOwnerId() == this.client.getHabbo().getHabboInfo().getId() || member.getRank().equals(GuildRank.OWNER); + boolean actorIsGlobalGuildAdmin = this.client.getHabbo().hasPermission(Permission.ACC_GUILD_ADMIN); + if ((targetMember.getRank().equals(GuildRank.ADMIN) || targetMember.getRank().equals(GuildRank.OWNER)) + && !actorIsGuildOwner + && !actorIsGlobalGuildAdmin) { + return; + } + if (userId == this.client.getHabbo().getHabboInfo().getId() || guild.getOwnerId() == this.client.getHabbo().getHabboInfo().getId() || member.getRank().equals(GuildRank.OWNER) || member.getRank().equals(GuildRank.ADMIN) || this.client.getHabbo().hasPermission(Permission.ACC_GUILD_ADMIN)) { Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId); GuildRemovedMemberEvent removedMemberEvent = new GuildRemovedMemberEvent(guild, userId, habbo); diff --git a/Emulator/src/test/java/com/eu/habbo/messages/incoming/guilds/GuildMemberRemovalPermissionContractTest.java b/Emulator/src/test/java/com/eu/habbo/messages/incoming/guilds/GuildMemberRemovalPermissionContractTest.java new file mode 100644 index 00000000..b031ab34 --- /dev/null +++ b/Emulator/src/test/java/com/eu/habbo/messages/incoming/guilds/GuildMemberRemovalPermissionContractTest.java @@ -0,0 +1,27 @@ +package com.eu.habbo.messages.incoming.guilds; + +import org.junit.jupiter.api.Test; + +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +class GuildMemberRemovalPermissionContractTest { + @Test + void regularAdminsCannotRemovePeerAdmins() throws Exception { + String source = Files.readString(Path.of("src/main/java/com/eu/habbo/messages/incoming/guilds/GuildRemoveMemberEvent.java")); + + int targetLookup = source.indexOf("GuildMember targetMember ="); + int peerAdminGuard = source.indexOf("targetMember.getRank().equals(GuildRank.ADMIN)", targetLookup); + int ownerCheck = source.indexOf("!actorIsGuildOwner", peerAdminGuard); + int globalCheck = source.indexOf("!actorIsGlobalGuildAdmin", ownerCheck); + int removeMember = source.indexOf("removeMember(guild, userId)", globalCheck); + + assertTrue(targetLookup > -1, "member removal should load the target membership row"); + assertTrue(peerAdminGuard > targetLookup, "member removal should detect admin targets"); + assertTrue(ownerCheck > peerAdminGuard, "peer-admin removal must require guild owner"); + assertTrue(globalCheck > ownerCheck, "peer-admin removal may also allow global guild admins"); + assertTrue(removeMember > globalCheck, "target rank authorization must run before removal"); + } +}