fix(forums): bound guild forum view inputs

This commit is contained in:
simoleo89
2026-06-16 20:37:48 +02:00
parent 416d0bb088
commit 9b9902c76d
6 changed files with 44 additions and 1 deletions
@@ -8,6 +8,7 @@ import com.eu.habbo.messages.incoming.MessageHandler;
import com.eu.habbo.messages.outgoing.generic.alerts.BubbleAlertComposer;
import com.eu.habbo.messages.outgoing.generic.alerts.BubbleAlertKeys;
import com.eu.habbo.messages.outgoing.guilds.forums.GuildForumDataComposer;
import com.eu.habbo.messages.outgoing.handshake.ConnectionErrorComposer;
public class GuildForumDataEvent extends MessageHandler {
@Override
@@ -19,6 +20,11 @@ public class GuildForumDataEvent extends MessageHandler {
public void handle() throws Exception {
int guildId = packet.readInt();
if (!GuildForumInputGuard.isPositiveId(guildId)) {
this.client.sendResponse(new ConnectionErrorComposer(400));
return;
}
Guild guild = Emulator.getGameEnvironment().getGuildManager().getGuild(guildId);
if (guild == null) return;
@@ -2,6 +2,7 @@ package com.eu.habbo.messages.incoming.guilds.forums;
final class GuildForumInputGuard {
static final int MAX_PAGE_LIMIT = 50;
static final int MAX_THREAD_INDEX = 1000;
static final int MAX_MARK_READ_BATCH = 50;
private GuildForumInputGuard() {
@@ -19,6 +20,10 @@ final class GuildForumInputGuard {
return index >= 0 && limit > 0 && limit <= MAX_PAGE_LIMIT;
}
static boolean isValidThreadIndex(int index) {
return index >= 0 && index <= MAX_THREAD_INDEX;
}
static boolean isValidMarkReadBatch(int count) {
return count > 0 && count <= MAX_MARK_READ_BATCH;
}
@@ -1,6 +1,9 @@
package com.eu.habbo.messages.incoming.guilds.forums;
import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.guilds.Guild;
import com.eu.habbo.habbohotel.guilds.GuildMember;
import com.eu.habbo.habbohotel.permissions.Permission;
import com.eu.habbo.messages.incoming.MessageHandler;
import com.eu.habbo.messages.outgoing.guilds.forums.GuildForumDataComposer;
import org.slf4j.Logger;
@@ -37,6 +40,17 @@ public class GuildForumMarkAsReadEvent extends MessageHandler {
continue;
}
Guild guild = Emulator.getGameEnvironment().getGuildManager().getGuild(guildId);
if (guild == null || !guild.hasForum()) {
continue;
}
GuildMember member = Emulator.getGameEnvironment().getGuildManager().getGuildMember(guildId, userId);
boolean staff = this.client.getHabbo().hasPermission(Permission.ACC_MODTOOL_TICKET_Q);
if (!guild.canHabboReadForum(userId, member, staff)) {
continue;
}
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement(
"INSERT INTO `guild_forum_views` (`user_id`, `guild_id`, `timestamp`) VALUES (?, ?, ?) " +
"ON DUPLICATE KEY UPDATE `timestamp` = ?"
@@ -22,7 +22,7 @@ public class GuildForumThreadsEvent extends MessageHandler {
int guildId = packet.readInt();
int index = packet.readInt();
if (!GuildForumInputGuard.isPositiveId(guildId) || index < 0) {
if (!GuildForumInputGuard.isPositiveId(guildId) || !GuildForumInputGuard.isValidThreadIndex(index)) {
this.client.sendResponse(new ConnectionErrorComposer(400));
return;
}
@@ -15,6 +15,7 @@ class GuildForumInputGuardContractTest {
for (String handler : List.of(
"GuildForumPostThreadEvent.java",
"GuildForumDataEvent.java",
"GuildForumModerateMessageEvent.java",
"GuildForumModerateThreadEvent.java",
"GuildForumThreadUpdateEvent.java",
@@ -39,9 +40,12 @@ class GuildForumInputGuardContractTest {
String settings = Files.readString(base.resolve("GuildForumUpdateSettingsEvent.java"));
String moderateThread = Files.readString(base.resolve("GuildForumModerateThreadEvent.java"));
String moderateMessage = Files.readString(base.resolve("GuildForumModerateMessageEvent.java"));
String threads = Files.readString(base.resolve("GuildForumThreadsEvent.java"));
assertTrue(messages.contains("GuildForumInputGuard.isValidPage(index, limit)"),
"thread message reads must bound index/limit before fetching comments");
assertTrue(threads.contains("GuildForumInputGuard.isValidThreadIndex(index)"),
"thread list reads must bound the client-provided index before composing results");
assertTrue(markRead.contains("GuildForumInputGuard.isValidMarkReadBatch(count)"),
"mark-as-read must bound the client-provided batch count before DB writes");
assertTrue(settings.contains("GuildForumInputGuard.isSettingsState"),
@@ -59,4 +63,16 @@ class GuildForumInputGuardContractTest {
assertTrue(source.contains("GuildForumInputGuard.normalize(this.packet.readString())"),
"forum post subject and body should be normalized before word filtering and length checks");
}
@Test
void markAsReadRequiresForumReadAccessBeforeWritingViews() throws Exception {
String source = Files.readString(Path.of("src/main/java/com/eu/habbo/messages/incoming/guilds/forums/GuildForumMarkAsReadEvent.java"));
int guildLookup = source.indexOf("Guild guild = Emulator.getGameEnvironment().getGuildManager().getGuild(guildId)");
int readGuard = source.indexOf("guild.canHabboReadForum(userId, member, staff)");
int insert = source.indexOf("INSERT INTO `guild_forum_views`");
assertTrue(guildLookup > -1 && readGuard > guildLookup && readGuard < insert,
"mark-as-read should confirm the user can read the forum before inserting view rows");
}
}
@@ -21,6 +21,8 @@ class GuildForumInputGuardTest {
assertFalse(GuildForumInputGuard.isValidPage(0, 0));
assertTrue(GuildForumInputGuard.isValidPage(0, GuildForumInputGuard.MAX_PAGE_LIMIT));
assertFalse(GuildForumInputGuard.isValidPage(0, GuildForumInputGuard.MAX_PAGE_LIMIT + 1));
assertTrue(GuildForumInputGuard.isValidThreadIndex(GuildForumInputGuard.MAX_THREAD_INDEX));
assertFalse(GuildForumInputGuard.isValidThreadIndex(GuildForumInputGuard.MAX_THREAD_INDEX + 1));
}
@Test