You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-20 07:26:18 +00:00
fix(rcon): validate offline badge targets
GiveBadge could treat a missing offline user as eligible for a badge and insert through a nullable user subquery. Depending on SQL mode this could fail late or persist an orphaned user_id value. Resolve the offline user first, return HABBO_NOT_FOUND when absent, and insert badges with the resolved user id only.
This commit is contained in:
@@ -3,6 +3,8 @@ package com.eu.habbo.messages.rcon;
|
|||||||
import com.eu.habbo.Emulator;
|
import com.eu.habbo.Emulator;
|
||||||
import com.eu.habbo.habbohotel.users.Habbo;
|
import com.eu.habbo.habbohotel.users.Habbo;
|
||||||
import com.eu.habbo.habbohotel.users.HabboBadge;
|
import com.eu.habbo.habbohotel.users.HabboBadge;
|
||||||
|
import com.eu.habbo.habbohotel.users.HabboInfo;
|
||||||
|
import com.eu.habbo.habbohotel.users.HabboManager;
|
||||||
import com.eu.habbo.messages.outgoing.users.AddUserBadgeComposer;
|
import com.eu.habbo.messages.outgoing.users.AddUserBadgeComposer;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
@@ -57,11 +59,18 @@ public class GiveBadge extends RCONMessage<GiveBadge.GiveBadgeJSON> {
|
|||||||
this.message = Emulator.getTexts().getValue("commands.succes.cmd_badge.given").replace("%user%", username).replace("%badge%", badgeCode);
|
this.message = Emulator.getTexts().getValue("commands.succes.cmd_badge.given").replace("%user%", username).replace("%badge%", badgeCode);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
HabboInfo habboInfo = HabboManager.getOfflineHabboInfo(json.user_id);
|
||||||
|
if (habboInfo == null) {
|
||||||
|
this.status = RCONMessage.HABBO_NOT_FOUND;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
username = habboInfo.getUsername();
|
||||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection()) {
|
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection()) {
|
||||||
for (String badgeCode : json.badge.split(";")) {
|
for (String badgeCode : json.badge.split(";")) {
|
||||||
int numberOfRows = 0;
|
int numberOfRows = 0;
|
||||||
try (PreparedStatement statement = connection.prepareStatement("SELECT COUNT(slot_id) FROM users_badges INNER JOIN users ON users.id = user_id WHERE users.id = ? AND badge_code = ? LIMIT 1")) {
|
try (PreparedStatement statement = connection.prepareStatement("SELECT COUNT(slot_id) FROM users_badges WHERE user_id = ? AND badge_code = ? LIMIT 1")) {
|
||||||
statement.setInt(1, json.user_id);
|
statement.setInt(1, habboInfo.getId());
|
||||||
statement.setString(2, badgeCode);
|
statement.setString(2, badgeCode);
|
||||||
try (ResultSet set = statement.executeQuery()) {
|
try (ResultSet set = statement.executeQuery()) {
|
||||||
if (set.next()){
|
if (set.next()){
|
||||||
@@ -74,8 +83,8 @@ public class GiveBadge extends RCONMessage<GiveBadge.GiveBadgeJSON> {
|
|||||||
this.status = RCONMessage.STATUS_ERROR;
|
this.status = RCONMessage.STATUS_ERROR;
|
||||||
this.message += Emulator.getTexts().getValue("commands.error.cmd_badge.already_owns").replace("%user%", username).replace("%badge%", badgeCode) + "\r";
|
this.message += Emulator.getTexts().getValue("commands.error.cmd_badge.already_owns").replace("%user%", username).replace("%badge%", badgeCode) + "\r";
|
||||||
} else {
|
} else {
|
||||||
try (PreparedStatement statement = connection.prepareStatement("INSERT INTO users_badges VALUES (null, (SELECT id FROM users WHERE users.id = ? LIMIT 1), 0, ?)", Statement.RETURN_GENERATED_KEYS)) {
|
try (PreparedStatement statement = connection.prepareStatement("INSERT INTO users_badges (`id`, `user_id`, `slot_id`, `badge_code`) VALUES (null, ?, 0, ?)", Statement.RETURN_GENERATED_KEYS)) {
|
||||||
statement.setInt(1, json.user_id);
|
statement.setInt(1, habboInfo.getId());
|
||||||
statement.setString(2, badgeCode);
|
statement.setString(2, badgeCode);
|
||||||
statement.execute();
|
statement.execute();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.eu.habbo.messages.rcon;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class GiveBadgeContractTest {
|
||||||
|
private static String giveBadgeSource() throws Exception {
|
||||||
|
return Files.readString(Path.of("src/main/java/com/eu/habbo/messages/rcon/GiveBadge.java"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void offlineBadgeGrantRequiresExistingUserBeforeInsert() throws Exception {
|
||||||
|
String source = giveBadgeSource();
|
||||||
|
|
||||||
|
assertTrue(source.contains("HabboManager.getOfflineHabboInfo(json.user_id)"),
|
||||||
|
"Offline RCON badge grants must verify the target user exists");
|
||||||
|
assertTrue(source.contains("RCONMessage.HABBO_NOT_FOUND"),
|
||||||
|
"Offline RCON badge grants must report missing users");
|
||||||
|
assertFalse(source.contains("(SELECT id FROM users WHERE users.id = ? LIMIT 1)"),
|
||||||
|
"Offline RCON badge grants must not insert through a nullable user subquery");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user