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): harden gift creation requests
This commit is contained in:
@@ -3,19 +3,14 @@ package com.eu.habbo.messages.rcon;
|
|||||||
import com.eu.habbo.Emulator;
|
import com.eu.habbo.Emulator;
|
||||||
import com.eu.habbo.habbohotel.items.Item;
|
import com.eu.habbo.habbohotel.items.Item;
|
||||||
import com.eu.habbo.habbohotel.users.Habbo;
|
import com.eu.habbo.habbohotel.users.Habbo;
|
||||||
|
import com.eu.habbo.habbohotel.users.HabboInfo;
|
||||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||||
|
import com.eu.habbo.habbohotel.users.HabboManager;
|
||||||
import com.eu.habbo.messages.outgoing.inventory.InventoryRefreshComposer;
|
import com.eu.habbo.messages.outgoing.inventory.InventoryRefreshComposer;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
public class SendGift extends RCONMessage<SendGift.SendGiftJSON> {
|
public class SendGift extends RCONMessage<SendGift.SendGiftJSON> {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(SendGift.class);
|
private static final int DEFAULT_MAX_MESSAGE_LENGTH = 300;
|
||||||
|
|
||||||
public SendGift() {
|
public SendGift() {
|
||||||
super(SendGiftJSON.class);
|
super(SendGiftJSON.class);
|
||||||
@@ -23,13 +18,13 @@ public class SendGift extends RCONMessage<SendGift.SendGiftJSON> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(Gson gson, SendGiftJSON json) {
|
public void handle(Gson gson, SendGiftJSON json) {
|
||||||
if (json.user_id < 0) {
|
if (json.user_id <= 0) {
|
||||||
this.status = RCONMessage.STATUS_ERROR;
|
this.status = RCONMessage.STATUS_ERROR;
|
||||||
this.message = Emulator.getTexts().getValue("commands.error.cmd_gift.user_not_found").replace("%username%", json.user_id + "");
|
this.message = Emulator.getTexts().getValue("commands.error.cmd_gift.user_not_found").replace("%username%", json.user_id + "");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.itemid < 0) {
|
if (json.itemid <= 0) {
|
||||||
this.status = RCONMessage.STATUS_ERROR;
|
this.status = RCONMessage.STATUS_ERROR;
|
||||||
this.message = Emulator.getTexts().getValue("commands.error.cmd_gift.not_a_number");
|
this.message = Emulator.getTexts().getValue("commands.error.cmd_gift.not_a_number");
|
||||||
return;
|
return;
|
||||||
@@ -42,50 +37,74 @@ public class SendGift extends RCONMessage<SendGift.SendGiftJSON> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean userFound;
|
if (!baseItem.allowGift()) {
|
||||||
Habbo habbo;
|
this.status = RCONMessage.STATUS_ERROR;
|
||||||
|
this.message = Emulator.getTexts().getValue("commands.error.cmd_gift.not_found").replace("%itemid%", json.itemid + "");
|
||||||
habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(json.user_id);
|
return;
|
||||||
|
|
||||||
userFound = habbo != null;
|
|
||||||
String username = "";
|
|
||||||
if (!userFound) {
|
|
||||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("SELECT * FROM users WHERE id = ? LIMIT 1")) {
|
|
||||||
statement.setInt(1, json.user_id);
|
|
||||||
try (ResultSet set = statement.executeQuery()) {
|
|
||||||
if (set.next()) {
|
|
||||||
username = set.getString("username");
|
|
||||||
userFound = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
LOGGER.error("Caught SQL exception", e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
username = habbo.getHabboInfo().getUsername();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userFound) {
|
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(json.user_id);
|
||||||
this.status = RCONMessage.STATUS_ERROR;
|
HabboInfo habboInfo = habbo != null ? habbo.getHabboInfo() : HabboManager.getOfflineHabboInfo(json.user_id);
|
||||||
this.message = Emulator.getTexts().getValue("commands.error.cmd_gift.user_not_found").replace("%username%", username);
|
if (habboInfo == null) {
|
||||||
|
this.status = RCONMessage.HABBO_NOT_FOUND;
|
||||||
|
this.message = Emulator.getTexts().getValue("commands.error.cmd_gift.user_not_found").replace("%username%", json.user_id + "");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HabboItem item = Emulator.getGameEnvironment().getItemManager().createItem(0, baseItem, 0, 0, "");
|
HabboItem item = Emulator.getGameEnvironment().getItemManager().createItem(0, baseItem, 0, 0, "");
|
||||||
Item giftItem = Emulator.getGameEnvironment().getItemManager().getItem((Integer) Emulator.getGameEnvironment().getCatalogManager().giftFurnis.values().toArray()[Emulator.getRandom().nextInt(Emulator.getGameEnvironment().getCatalogManager().giftFurnis.size())]);
|
Item giftItem = this.randomGiftItem();
|
||||||
|
if (item == null || giftItem == null) {
|
||||||
|
this.status = RCONMessage.SYSTEM_ERROR;
|
||||||
|
this.message = "gift configuration unavailable";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String extraData = "1\t" + item.getId();
|
String extraData = "1\t" + item.getId();
|
||||||
extraData += "\t0\t0\t0\t" + json.message + "\t0\t0";
|
extraData += "\t0\t0\t0\t" + sanitizeGiftMessage(json.message) + "\t0\t0";
|
||||||
|
|
||||||
Emulator.getGameEnvironment().getItemManager().createGift(username, giftItem, extraData, 0, 0);
|
if (Emulator.getGameEnvironment().getItemManager().createGift(habboInfo.getUsername(), giftItem, extraData, 0, 0) == null) {
|
||||||
|
this.status = RCONMessage.SYSTEM_ERROR;
|
||||||
|
this.message = "failed to create gift";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.message = Emulator.getTexts().getValue("commands.succes.cmd_gift").replace("%username%", username).replace("%itemname%", item.getBaseItem().getName());
|
this.message = Emulator.getTexts().getValue("commands.succes.cmd_gift").replace("%username%", habboInfo.getUsername()).replace("%itemname%", item.getBaseItem().getName());
|
||||||
|
|
||||||
if (habbo != null) {
|
if (habbo != null) {
|
||||||
habbo.getClient().sendResponse(new InventoryRefreshComposer());
|
habbo.getClient().sendResponse(new InventoryRefreshComposer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Item randomGiftItem() {
|
||||||
|
synchronized (Emulator.getGameEnvironment().getCatalogManager().giftFurnis) {
|
||||||
|
int size = Emulator.getGameEnvironment().getCatalogManager().giftFurnis.size();
|
||||||
|
if (size == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object[] giftIds = Emulator.getGameEnvironment().getCatalogManager().giftFurnis.values().toArray();
|
||||||
|
return Emulator.getGameEnvironment().getItemManager().getItem((Integer) giftIds[Emulator.getRandom().nextInt(size)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String sanitizeGiftMessage(String message) {
|
||||||
|
int maxLength = Emulator.getConfig().getInt("hotel.gifts.length.max", DEFAULT_MAX_MESSAGE_LENGTH);
|
||||||
|
if (maxLength <= 0) {
|
||||||
|
maxLength = DEFAULT_MAX_MESSAGE_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
String sanitized = message.replace('\t', ' ').replace('\r', ' ').replace('\n', ' ');
|
||||||
|
if (sanitized.length() > maxLength) {
|
||||||
|
return sanitized.substring(0, maxLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sanitized;
|
||||||
|
}
|
||||||
|
|
||||||
static class SendGiftJSON {
|
static class SendGiftJSON {
|
||||||
|
|
||||||
public int user_id = -1;
|
public int user_id = -1;
|
||||||
@@ -96,4 +115,4 @@ public class SendGift extends RCONMessage<SendGift.SendGiftJSON> {
|
|||||||
|
|
||||||
public String message = "";
|
public String message = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
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.assertTrue;
|
||||||
|
|
||||||
|
class SendGiftContractTest {
|
||||||
|
private static String source() throws Exception {
|
||||||
|
return Files.readString(Path.of("src/main/java/com/eu/habbo/messages/rcon/SendGift.java"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void validatesGiftTargetsAndItemsBeforeCreatingInventoryRows() throws Exception {
|
||||||
|
String source = source();
|
||||||
|
|
||||||
|
assertTrue(source.contains("json.user_id <= 0"),
|
||||||
|
"RCON gifts must reject invalid target users");
|
||||||
|
assertTrue(source.contains("json.itemid <= 0"),
|
||||||
|
"RCON gifts must reject invalid item ids");
|
||||||
|
assertTrue(source.contains("baseItem.allowGift()"),
|
||||||
|
"RCON gifts must respect the item giftability flag");
|
||||||
|
assertTrue(source.contains("HabboManager.getOfflineHabboInfo(json.user_id)"),
|
||||||
|
"RCON gifts must resolve offline users through HabboManager");
|
||||||
|
assertTrue(source.contains("HABBO_NOT_FOUND"),
|
||||||
|
"RCON gifts must report missing users with the RCON missing-user status");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void sanitizesGiftMessageAndHandlesMissingGiftConfiguration() throws Exception {
|
||||||
|
String source = source();
|
||||||
|
|
||||||
|
assertTrue(source.contains("sanitizeGiftMessage(json.message)"),
|
||||||
|
"RCON gift extraData must use a sanitized message");
|
||||||
|
assertTrue(source.contains("replace('\\t', ' ').replace('\\r', ' ').replace('\\n', ' ')"),
|
||||||
|
"RCON gift messages must not inject gift extraData delimiters");
|
||||||
|
assertTrue(source.contains("hotel.gifts.length.max"),
|
||||||
|
"RCON gift messages must respect the configured gift length limit");
|
||||||
|
assertTrue(source.contains("giftFurnis.size()"),
|
||||||
|
"RCON gift creation must guard against empty gift wrapper configuration");
|
||||||
|
assertTrue(source.contains("createGift(habboInfo.getUsername()"),
|
||||||
|
"RCON gifts must create the wrapper for the canonical target username");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user