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(rcon): validate privileged payloads
This commit is contained in:
@@ -5,6 +5,10 @@ import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.HabboBadge;
|
||||
import com.eu.habbo.messages.outgoing.users.AddUserBadgeComposer;
|
||||
import com.google.gson.Gson;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -89,9 +93,13 @@ public class GiveBadge extends RCONMessage<GiveBadge.GiveBadgeJSON> {
|
||||
|
||||
static class GiveBadgeJSON {
|
||||
|
||||
@Positive(message = "invalid user")
|
||||
public int user_id = -1;
|
||||
|
||||
|
||||
@NotBlank(message = "invalid badge")
|
||||
@Size(max = 512, message = "invalid badge")
|
||||
@Pattern(regexp = "[A-Za-z0-9_\\-;]+", message = "invalid badge")
|
||||
public String badge;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.eu.habbo.messages.rcon;
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.google.gson.Gson;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -40,9 +41,11 @@ public class GiveCredits extends RCONMessage<GiveCredits.JSONGiveCredits> {
|
||||
|
||||
static class JSONGiveCredits {
|
||||
|
||||
@Positive(message = "invalid user")
|
||||
public int user_id;
|
||||
|
||||
|
||||
@Positive(message = "invalid credits")
|
||||
public int credits;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.eu.habbo.messages.rcon;
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.google.gson.Gson;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -40,9 +41,11 @@ public class GivePixels extends RCONMessage<GivePixels.JSONGivePixels> {
|
||||
|
||||
static class JSONGivePixels {
|
||||
|
||||
@Positive(message = "invalid user")
|
||||
public int user_id;
|
||||
|
||||
|
||||
@Positive(message = "invalid pixels")
|
||||
public int pixels;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.eu.habbo.messages.rcon;
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.google.gson.Gson;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -42,12 +44,15 @@ public class GivePoints extends RCONMessage<GivePoints.JSONGivePoints> {
|
||||
|
||||
static class JSONGivePoints {
|
||||
|
||||
@Positive(message = "invalid user")
|
||||
public int user_id;
|
||||
|
||||
|
||||
@Positive(message = "invalid points")
|
||||
public int points;
|
||||
|
||||
|
||||
@Min(value = 0, message = "invalid currency type")
|
||||
public int type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,17 @@ public abstract class RCONMessage<T> {
|
||||
|
||||
public abstract void handle(Gson gson, T json);
|
||||
|
||||
public boolean validate(T json) {
|
||||
String validationError = RconPayloadValidator.validate(json);
|
||||
if (validationError == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this.status = STATUS_ERROR;
|
||||
this.message = validationError;
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static class RCONMessageSerializer implements JsonSerializer<RCONMessage> {
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.eu.habbo.messages.rcon;
|
||||
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.Validation;
|
||||
import jakarta.validation.Validator;
|
||||
import jakarta.validation.ValidatorFactory;
|
||||
import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Set;
|
||||
|
||||
final class RconPayloadValidator {
|
||||
private static final Validator VALIDATOR;
|
||||
|
||||
static {
|
||||
ValidatorFactory factory = Validation.byDefaultProvider()
|
||||
.configure()
|
||||
.messageInterpolator(new ParameterMessageInterpolator())
|
||||
.buildValidatorFactory();
|
||||
VALIDATOR = factory.getValidator();
|
||||
}
|
||||
|
||||
private RconPayloadValidator() {
|
||||
}
|
||||
|
||||
static String validate(Object payload) {
|
||||
if (payload == null) {
|
||||
return "invalid payload";
|
||||
}
|
||||
|
||||
Set<ConstraintViolation<Object>> violations = VALIDATOR.validate(payload);
|
||||
return violations.stream()
|
||||
.min(Comparator.comparing(violation -> violation.getPropertyPath().toString()))
|
||||
.map(ConstraintViolation::getMessage)
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.eu.habbo.messages.rcon;
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.google.gson.Gson;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
|
||||
public class SetRank extends RCONMessage<SetRank.JSONSetRank> {
|
||||
|
||||
@@ -31,9 +32,11 @@ public class SetRank extends RCONMessage<SetRank.JSONSetRank> {
|
||||
|
||||
static class JSONSetRank {
|
||||
|
||||
@Positive(message = "invalid user")
|
||||
public int user_id;
|
||||
|
||||
|
||||
@Positive(message = "invalid rank")
|
||||
public int rank;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,10 @@ public class RCONServer extends Server {
|
||||
try {
|
||||
RCONMessage rcon = message.getDeclaredConstructor().newInstance();
|
||||
Gson gson = this.gsonBuilder.create();
|
||||
rcon.handle(gson, gson.fromJson(body, rcon.type));
|
||||
Object payload = gson.fromJson(body, rcon.type);
|
||||
if (rcon.validate(payload)) {
|
||||
rcon.handle(gson, payload);
|
||||
}
|
||||
LOGGER.info("Handled RCON Message: {}", message.getSimpleName());
|
||||
result = gson.toJson(rcon, RCONMessage.class);
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
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 RconPayloadValidatorTest {
|
||||
@Test
|
||||
void acceptsValidAnnotatedPayloads() {
|
||||
SetRank.JSONSetRank payload = new SetRank.JSONSetRank();
|
||||
payload.user_id = 1;
|
||||
payload.rank = 2;
|
||||
|
||||
assertNull(RconPayloadValidator.validate(payload));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsInvalidSetRankPayloadsBeforeDispatch() {
|
||||
SetRank.JSONSetRank payload = new SetRank.JSONSetRank();
|
||||
payload.user_id = 0;
|
||||
payload.rank = 2;
|
||||
|
||||
assertEquals("invalid user", RconPayloadValidator.validate(payload));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsInvalidGrantPayloadsBeforeDispatch() {
|
||||
GiveCredits.JSONGiveCredits payload = new GiveCredits.JSONGiveCredits();
|
||||
payload.user_id = 1;
|
||||
payload.credits = 0;
|
||||
|
||||
assertEquals("invalid credits", RconPayloadValidator.validate(payload));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsBlankBadgePayloadsBeforeDispatch() {
|
||||
GiveBadge.GiveBadgeJSON payload = new GiveBadge.GiveBadgeJSON();
|
||||
payload.user_id = 1;
|
||||
payload.badge = " ";
|
||||
|
||||
assertEquals("invalid badge", RconPayloadValidator.validate(payload));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user