fix(rcon): constrain setrank requests

This commit is contained in:
simoleo89
2026-06-14 16:29:15 +02:00
parent 775197984f
commit 3cb24a5185
3 changed files with 111 additions and 0 deletions
@@ -5,6 +5,10 @@ import com.eu.habbo.habbohotel.users.Habbo;
import com.google.gson.Gson;
import jakarta.validation.constraints.Positive;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class SetRank extends RCONMessage<SetRank.JSONSetRank> {
public SetRank() {
@@ -13,6 +17,25 @@ public class SetRank extends RCONMessage<SetRank.JSONSetRank> {
@Override
public void handle(Gson gson, JSONSetRank object) {
int maxRank = SetRankRequestGuard.parseMaxRank(
Emulator.getConfig().getValue("rcon.setrank.max_rank", String.valueOf(SetRankRequestGuard.DEFAULT_MAX_RANK)));
String validationError = SetRankRequestGuard.validate(
object.user_id,
object.rank,
maxRank,
rankId -> Emulator.getGameEnvironment().getPermissionsManager().rankExists(rankId));
if (validationError != null) {
this.status = RCONMessage.STATUS_ERROR;
this.message = validationError;
return;
}
if (!userExists(object.user_id)) {
this.status = RCONMessage.HABBO_NOT_FOUND;
this.message = "user not found";
return;
}
try {
Emulator.getGameEnvironment().getHabboManager().setRank(object.user_id, object.rank);
} catch (Exception e) {
@@ -30,6 +53,23 @@ public class SetRank extends RCONMessage<SetRank.JSONSetRank> {
}
}
private static boolean userExists(int userId) {
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId);
if (habbo != null) {
return true;
}
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT id FROM users WHERE id = ? LIMIT 1")) {
statement.setInt(1, userId);
try (ResultSet set = statement.executeQuery()) {
return set.next();
}
} catch (Exception e) {
return false;
}
}
static class JSONSetRank {
@Positive(message = "invalid user")
@@ -0,0 +1,39 @@
package com.eu.habbo.messages.rcon;
import java.util.function.IntPredicate;
public class SetRankRequestGuard {
public static final int DEFAULT_MAX_RANK = 12;
private SetRankRequestGuard() {
}
public static String validate(int userId, int rankId, int maxRank, IntPredicate rankExists) {
if (userId <= 0) {
return "invalid user";
}
if (rankId <= 0) {
return "invalid rank";
}
if (maxRank > 0 && rankId > maxRank) {
return "rank exceeds rcon ceiling";
}
if (!rankExists.test(rankId)) {
return "invalid rank";
}
return null;
}
public static int parseMaxRank(String rawValue) {
try {
int value = Integer.parseInt(rawValue);
return value > 0 ? value : DEFAULT_MAX_RANK;
} catch (Exception e) {
return DEFAULT_MAX_RANK;
}
}
}
@@ -0,0 +1,32 @@
package com.eu.habbo.messages.rcon;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
class SetRankRequestGuardTest {
@Test
void acceptsKnownRanksWithinTheRconCeiling() {
assertNull(SetRankRequestGuard.validate(1, 5, 12, rankId -> rankId == 5));
}
@Test
void rejectsInvalidUsersRanksAndUnknownRanks() {
assertEquals("invalid user", SetRankRequestGuard.validate(0, 5, 12, rankId -> true));
assertEquals("invalid rank", SetRankRequestGuard.validate(1, 0, 12, rankId -> true));
assertEquals("invalid rank", SetRankRequestGuard.validate(1, 5, 12, rankId -> false));
}
@Test
void rejectsRanksAboveConfiguredCeiling() {
assertEquals("rank exceeds rcon ceiling", SetRankRequestGuard.validate(1, 13, 12, rankId -> true));
}
@Test
void parsesInvalidMaxRankAsDefaultCeiling() {
assertEquals(SetRankRequestGuard.DEFAULT_MAX_RANK, SetRankRequestGuard.parseMaxRank(null));
assertEquals(SetRankRequestGuard.DEFAULT_MAX_RANK, SetRankRequestGuard.parseMaxRank("0"));
assertEquals(7, SetRankRequestGuard.parseMaxRank("7"));
}
}