You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-19 15:06:19 +00:00
fix(catalog): bound marketplace inputs
This commit is contained in:
@@ -58,6 +58,10 @@ public class MarketPlace {
|
||||
public static void takeBackItem(Habbo habbo, int offerId) {
|
||||
MarketPlaceOffer offer = habbo.getInventory().getOffer(offerId);
|
||||
|
||||
if (offer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Emulator.getPluginManager().fireEvent(new MarketPlaceItemCancelledEvent(offer)).isCancelled()) {
|
||||
takeBackItem(habbo, offer);
|
||||
}
|
||||
|
||||
+4
@@ -13,6 +13,10 @@ public class BuyItemEvent extends MessageHandler {
|
||||
public void handle() throws Exception {
|
||||
int offerId = this.packet.readInt();
|
||||
|
||||
if (!MarketplaceInputGuard.isPositiveId(offerId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MarketPlace.buyItem(offerId, this.client);
|
||||
}
|
||||
}
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.eu.habbo.messages.incoming.catalog.marketplace;
|
||||
|
||||
import com.eu.habbo.habbohotel.catalog.marketplace.MarketPlace;
|
||||
|
||||
final class MarketplaceInputGuard {
|
||||
static final int MAX_SEARCH_LENGTH = 30;
|
||||
static final int DEFAULT_SORT = 1;
|
||||
static final int MIN_SORT = 1;
|
||||
static final int MAX_SORT = 6;
|
||||
|
||||
private MarketplaceInputGuard() {
|
||||
}
|
||||
|
||||
static boolean isPositiveId(int id) {
|
||||
return id > 0;
|
||||
}
|
||||
|
||||
static String normalizeSearch(String query) {
|
||||
if (query == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String normalized = query.trim();
|
||||
return normalized.length() > MAX_SEARCH_LENGTH ? normalized.substring(0, MAX_SEARCH_LENGTH) : normalized;
|
||||
}
|
||||
|
||||
static int normalizeSort(int sort) {
|
||||
return sort >= MIN_SORT && sort <= MAX_SORT ? sort : DEFAULT_SORT;
|
||||
}
|
||||
|
||||
static int normalizeMinPrice(int minPrice) {
|
||||
if (minPrice == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return Math.max(0, Math.min(minPrice, MarketPlace.MAXIMUM_LISTING_PRICE));
|
||||
}
|
||||
|
||||
static int normalizeMaxPrice(int maxPrice, int minPrice) {
|
||||
if (maxPrice == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int normalized = Math.max(0, Math.min(maxPrice, MarketPlace.MAXIMUM_LISTING_PRICE));
|
||||
return minPrice > 0 && normalized > 0 && normalized < minPrice ? minPrice : normalized;
|
||||
}
|
||||
}
|
||||
+4
@@ -9,6 +9,10 @@ public class RequestItemInfoEvent extends MessageHandler {
|
||||
this.packet.readInt();
|
||||
int id = this.packet.readInt();
|
||||
|
||||
if (!MarketplaceInputGuard.isPositiveId(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.client.sendResponse(new MarketplaceItemInfoComposer(id));
|
||||
}
|
||||
}
|
||||
|
||||
+4
-8
@@ -20,14 +20,10 @@ public class RequestOffersEvent extends MessageHandler {
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
int min = this.packet.readInt();
|
||||
int max = this.packet.readInt();
|
||||
String query = this.packet.readString();
|
||||
int type = this.packet.readInt();
|
||||
|
||||
if (query.length() > 30) {
|
||||
query = query.substring(0, 30);
|
||||
}
|
||||
int min = MarketplaceInputGuard.normalizeMinPrice(this.packet.readInt());
|
||||
int max = MarketplaceInputGuard.normalizeMaxPrice(this.packet.readInt(), min);
|
||||
String query = MarketplaceInputGuard.normalizeSearch(this.packet.readString());
|
||||
int type = MarketplaceInputGuard.normalizeSort(this.packet.readInt());
|
||||
|
||||
|
||||
boolean tryCache = min == -1 && max == -1 && query.isEmpty();
|
||||
|
||||
+1
@@ -29,6 +29,7 @@ public class SellItemEvent extends MessageHandler {
|
||||
final int furniType = this.packet.readInt(); // 1 = FLOOR_TYPE, 2 = WALL_TYPE
|
||||
final int itemId = this.packet.readInt();
|
||||
|
||||
if (!MarketplaceInputGuard.isPositiveId(itemId)) return;
|
||||
if (furniType != 1 && furniType != 2) return;
|
||||
|
||||
HabboItem item = this.client.getHabbo().getInventory().getItemsComponent().getHabboItem(itemId);
|
||||
|
||||
+5
@@ -12,6 +12,11 @@ public class TakeBackItemEvent extends MessageHandler {
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
int offerId = this.packet.readInt();
|
||||
|
||||
if (!MarketplaceInputGuard.isPositiveId(offerId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MarketPlace.takeBackItem(this.client.getHabbo(), offerId);
|
||||
}
|
||||
}
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.eu.habbo.messages.incoming.catalog.marketplace;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class MarketplaceInputContractTest {
|
||||
@Test
|
||||
void marketplaceIdHandlersRejectNonPositiveIds() throws Exception {
|
||||
Path base = Path.of("src/main/java/com/eu/habbo/messages/incoming/catalog/marketplace");
|
||||
|
||||
for (String handler : List.of(
|
||||
"BuyItemEvent.java",
|
||||
"RequestItemInfoEvent.java",
|
||||
"SellItemEvent.java",
|
||||
"TakeBackItemEvent.java"
|
||||
)) {
|
||||
String source = Files.readString(base.resolve(handler));
|
||||
|
||||
assertTrue(source.contains("MarketplaceInputGuard.isPositiveId"),
|
||||
handler + " must reject zero or negative ids before marketplace or inventory lookup");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void offerSearchNormalizesCacheKeyInputs() throws Exception {
|
||||
String source = Files.readString(Path.of("src/main/java/com/eu/habbo/messages/incoming/catalog/marketplace/RequestOffersEvent.java"));
|
||||
|
||||
assertTrue(source.contains("MarketplaceInputGuard.normalizeMinPrice"),
|
||||
"marketplace offer search must normalize minimum price");
|
||||
assertTrue(source.contains("MarketplaceInputGuard.normalizeMaxPrice"),
|
||||
"marketplace offer search must normalize maximum price");
|
||||
assertTrue(source.contains("MarketplaceInputGuard.normalizeSearch"),
|
||||
"marketplace offer search must trim and bound search text");
|
||||
assertTrue(source.contains("MarketplaceInputGuard.normalizeSort"),
|
||||
"marketplace offer search must normalize sort before using it as a cache key");
|
||||
}
|
||||
|
||||
@Test
|
||||
void takeBackDoesNotFirePluginEventForMissingOffer() throws Exception {
|
||||
String source = Files.readString(Path.of("src/main/java/com/eu/habbo/habbohotel/catalog/marketplace/MarketPlace.java"));
|
||||
|
||||
assertTrue(source.contains("if (offer == null)"),
|
||||
"takeBackItem must ignore missing offers before constructing plugin events");
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.eu.habbo.messages.incoming.catalog.marketplace;
|
||||
|
||||
import com.eu.habbo.habbohotel.catalog.marketplace.MarketPlace;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class MarketplaceInputGuardTest {
|
||||
@Test
|
||||
void idsMustBePositive() {
|
||||
assertFalse(MarketplaceInputGuard.isPositiveId(0));
|
||||
assertFalse(MarketplaceInputGuard.isPositiveId(-1));
|
||||
assertTrue(MarketplaceInputGuard.isPositiveId(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void searchIsTrimmedAndBounded() {
|
||||
assertEquals("", MarketplaceInputGuard.normalizeSearch(null));
|
||||
assertEquals("rare", MarketplaceInputGuard.normalizeSearch(" rare "));
|
||||
assertEquals(MarketplaceInputGuard.MAX_SEARCH_LENGTH, MarketplaceInputGuard.normalizeSearch("a".repeat(80)).length());
|
||||
}
|
||||
|
||||
@Test
|
||||
void sortFallsBackToDefaultOutsideKnownRange() {
|
||||
assertEquals(MarketplaceInputGuard.DEFAULT_SORT, MarketplaceInputGuard.normalizeSort(0));
|
||||
assertEquals(3, MarketplaceInputGuard.normalizeSort(3));
|
||||
assertEquals(MarketplaceInputGuard.DEFAULT_SORT, MarketplaceInputGuard.normalizeSort(7));
|
||||
}
|
||||
|
||||
@Test
|
||||
void priceRangesPreserveCacheSentinelAndStayBounded() {
|
||||
assertEquals(-1, MarketplaceInputGuard.normalizeMinPrice(-1));
|
||||
assertEquals(0, MarketplaceInputGuard.normalizeMinPrice(-100));
|
||||
assertEquals(MarketPlace.MAXIMUM_LISTING_PRICE, MarketplaceInputGuard.normalizeMinPrice(Integer.MAX_VALUE));
|
||||
|
||||
assertEquals(-1, MarketplaceInputGuard.normalizeMaxPrice(-1, -1));
|
||||
assertEquals(500, MarketplaceInputGuard.normalizeMaxPrice(100, 500));
|
||||
assertEquals(MarketPlace.MAXIMUM_LISTING_PRICE, MarketplaceInputGuard.normalizeMaxPrice(Integer.MAX_VALUE, 0));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user