fix(rcon): validate grant requests

This commit is contained in:
simoleo89
2026-06-14 16:45:04 +02:00
parent 3cb24a5185
commit dba0337a7b
11 changed files with 237 additions and 1 deletions
@@ -21,6 +21,18 @@ public class GiveCredits extends RCONMessage<GiveCredits.JSONGiveCredits> {
@Override
public void handle(Gson gson, JSONGiveCredits object) {
int maxAmount = RconGrantGuard.parseMaxAmount(
Emulator.getConfig().getValue("rcon.grant.max_amount", String.valueOf(RconGrantGuard.DEFAULT_MAX_AMOUNT)));
String validationError = RconGrantGuard.validateUserId(object.user_id);
if (validationError == null) {
validationError = RconGrantGuard.validatePositiveAmount(object.credits, maxAmount, "credits");
}
if (validationError != null) {
this.status = RCONMessage.STATUS_ERROR;
this.message = validationError;
return;
}
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(object.user_id);
if (habbo != null) {
@@ -21,11 +21,29 @@ public class GivePixels extends RCONMessage<GivePixels.JSONGivePixels> {
@Override
public void handle(Gson gson, JSONGivePixels object) {
int maxAmount = RconGrantGuard.parseMaxAmount(
Emulator.getConfig().getValue("rcon.grant.max_amount", String.valueOf(RconGrantGuard.DEFAULT_MAX_AMOUNT)));
String validationError = RconGrantGuard.validateUserId(object.user_id);
if (validationError == null) {
validationError = RconGrantGuard.validatePositiveAmount(object.pixels, maxAmount, "pixels");
}
if (validationError != null) {
this.status = RCONMessage.STATUS_ERROR;
this.message = validationError;
return;
}
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(object.user_id);
if (habbo != null) {
habbo.givePixels(object.pixels);
} else {
if (!RconUserLookup.userExists(object.user_id)) {
this.status = RCONMessage.HABBO_NOT_FOUND;
this.message = "user not found";
return;
}
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("INSERT INTO users_currency (`user_id`, `type`, `amount`) VALUES (?, 0, ?) ON DUPLICATE KEY UPDATE amount = amount + ?")) {
statement.setInt(1, object.user_id);
statement.setInt(2, object.pixels);
@@ -22,11 +22,32 @@ public class GivePoints extends RCONMessage<GivePoints.JSONGivePoints> {
@Override
public void handle(Gson gson, JSONGivePoints object) {
int maxAmount = RconGrantGuard.parseMaxAmount(
Emulator.getConfig().getValue("rcon.grant.max_amount", String.valueOf(RconGrantGuard.DEFAULT_MAX_AMOUNT)));
String validationError = RconGrantGuard.validateUserId(object.user_id);
if (validationError == null) {
validationError = RconGrantGuard.validateCurrencyType(object.type);
}
if (validationError == null) {
validationError = RconGrantGuard.validatePositiveAmount(object.points, maxAmount, "points");
}
if (validationError != null) {
this.status = RCONMessage.STATUS_ERROR;
this.message = validationError;
return;
}
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(object.user_id);
if (habbo != null) {
habbo.givePoints(object.type, object.points);
} else {
if (!RconUserLookup.userExists(object.user_id)) {
this.status = RCONMessage.HABBO_NOT_FOUND;
this.message = "user not found";
return;
}
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("INSERT INTO users_currency (`user_id`, `type`, `amount`) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE amount = amount + ?")) {
statement.setInt(1, object.user_id);
statement.setInt(2, object.type);
@@ -21,6 +21,27 @@ public class GiveRespect extends RCONMessage<GiveRespect.JSONGiveRespect> {
@Override
public void handle(Gson gson, JSONGiveRespect object) {
int maxAmount = RconGrantGuard.parseMaxAmount(
Emulator.getConfig().getValue("rcon.grant.max_amount", String.valueOf(RconGrantGuard.DEFAULT_MAX_AMOUNT)));
String validationError = RconGrantGuard.validateUserId(object.user_id);
if (validationError == null) {
validationError = RconGrantGuard.validateNonNegativeAmount(object.respect_given, maxAmount, "respect_given");
}
if (validationError == null) {
validationError = RconGrantGuard.validateNonNegativeAmount(object.respect_received, maxAmount, "respect_received");
}
if (validationError == null) {
validationError = RconGrantGuard.validateNonNegativeAmount(object.daily_respects, maxAmount, "daily_respects");
}
if (validationError == null && object.respect_given == 0 && object.respect_received == 0 && object.daily_respects == 0) {
validationError = "no respect grant provided";
}
if (validationError != null) {
this.status = RCONMessage.STATUS_ERROR;
this.message = validationError;
return;
}
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(object.user_id);
if (habbo != null) {
@@ -29,15 +50,26 @@ public class GiveRespect extends RCONMessage<GiveRespect.JSONGiveRespect> {
habbo.getHabboStats().respectPointsToGive += object.daily_respects;
habbo.getClient().sendResponse(new UserDataComposer(habbo));
} else {
if (!RconUserLookup.userExists(object.user_id)) {
this.status = RCONMessage.HABBO_NOT_FOUND;
this.message = "user not found";
return;
}
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("UPDATE users_settings SET respects_given = respects_given + ?, respects_received = respects_received + ?, daily_respect_points = daily_respect_points + ? WHERE user_id = ? LIMIT 1")) {
statement.setInt(1, object.respect_given);
statement.setInt(2, object.respect_received);
statement.setInt(3, object.daily_respects);
statement.setInt(4, object.user_id);
statement.execute();
if (statement.executeUpdate() == 0) {
this.status = RCONMessage.HABBO_NOT_FOUND;
this.message = "user not found";
return;
}
} catch (SQLException e) {
this.status = RCONMessage.SYSTEM_ERROR;
LOGGER.error("Caught SQL exception", e);
return;
}
this.message = "offline";
@@ -0,0 +1,49 @@
package com.eu.habbo.messages.rcon;
public class RconGrantGuard {
public static final int DEFAULT_MAX_AMOUNT = 1_000_000;
private RconGrantGuard() {
}
public static String validateUserId(int userId) {
return userId > 0 ? null : "invalid user";
}
public static String validatePositiveAmount(int amount, int maxAmount, String fieldName) {
if (amount <= 0) {
return "invalid " + fieldName;
}
if (maxAmount > 0 && amount > maxAmount) {
return fieldName + " exceeds rcon grant ceiling";
}
return null;
}
public static String validateNonNegativeAmount(int amount, int maxAmount, String fieldName) {
if (amount < 0) {
return "invalid " + fieldName;
}
if (maxAmount > 0 && amount > maxAmount) {
return fieldName + " exceeds rcon grant ceiling";
}
return null;
}
public static String validateCurrencyType(int type) {
return type >= 0 ? null : "invalid currency type";
}
public static int parseMaxAmount(String rawValue) {
try {
int value = Integer.parseInt(rawValue);
return value > 0 ? value : DEFAULT_MAX_AMOUNT;
} catch (Exception e) {
return DEFAULT_MAX_AMOUNT;
}
}
}
@@ -0,0 +1,28 @@
package com.eu.habbo.messages.rcon;
import com.eu.habbo.Emulator;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class RconUserLookup {
private RconUserLookup() {
}
public static boolean userExists(int userId) {
if (Emulator.getGameEnvironment().getHabboManager().getHabbo(userId) != 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;
}
}
}