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 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.habbohotel.users.HabboBadge;
|
||||||
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.Pattern;
|
||||||
|
import jakarta.validation.constraints.Positive;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -89,9 +93,13 @@ public class GiveBadge extends RCONMessage<GiveBadge.GiveBadgeJSON> {
|
|||||||
|
|
||||||
static class GiveBadgeJSON {
|
static class GiveBadgeJSON {
|
||||||
|
|
||||||
|
@Positive(message = "invalid user")
|
||||||
public int user_id = -1;
|
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;
|
public String badge;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ 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.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import jakarta.validation.constraints.Positive;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -40,9 +41,11 @@ public class GiveCredits extends RCONMessage<GiveCredits.JSONGiveCredits> {
|
|||||||
|
|
||||||
static class JSONGiveCredits {
|
static class JSONGiveCredits {
|
||||||
|
|
||||||
|
@Positive(message = "invalid user")
|
||||||
public int user_id;
|
public int user_id;
|
||||||
|
|
||||||
|
|
||||||
|
@Positive(message = "invalid credits")
|
||||||
public int credits;
|
public int credits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ 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.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import jakarta.validation.constraints.Positive;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -40,9 +41,11 @@ public class GivePixels extends RCONMessage<GivePixels.JSONGivePixels> {
|
|||||||
|
|
||||||
static class JSONGivePixels {
|
static class JSONGivePixels {
|
||||||
|
|
||||||
|
@Positive(message = "invalid user")
|
||||||
public int user_id;
|
public int user_id;
|
||||||
|
|
||||||
|
|
||||||
|
@Positive(message = "invalid pixels")
|
||||||
public int pixels;
|
public int pixels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
|
import jakarta.validation.constraints.Positive;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -42,12 +44,15 @@ public class GivePoints extends RCONMessage<GivePoints.JSONGivePoints> {
|
|||||||
|
|
||||||
static class JSONGivePoints {
|
static class JSONGivePoints {
|
||||||
|
|
||||||
|
@Positive(message = "invalid user")
|
||||||
public int user_id;
|
public int user_id;
|
||||||
|
|
||||||
|
|
||||||
|
@Positive(message = "invalid points")
|
||||||
public int points;
|
public int points;
|
||||||
|
|
||||||
|
|
||||||
|
@Min(value = 0, message = "invalid currency type")
|
||||||
public int type;
|
public int type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,17 @@ public abstract class RCONMessage<T> {
|
|||||||
|
|
||||||
public abstract void handle(Gson gson, T json);
|
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")
|
@SuppressWarnings("rawtypes")
|
||||||
public static class RCONMessageSerializer implements JsonSerializer<RCONMessage> {
|
public static class RCONMessageSerializer implements JsonSerializer<RCONMessage> {
|
||||||
@Override
|
@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.Emulator;
|
||||||
import com.eu.habbo.habbohotel.users.Habbo;
|
import com.eu.habbo.habbohotel.users.Habbo;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import jakarta.validation.constraints.Positive;
|
||||||
|
|
||||||
public class SetRank extends RCONMessage<SetRank.JSONSetRank> {
|
public class SetRank extends RCONMessage<SetRank.JSONSetRank> {
|
||||||
|
|
||||||
@@ -31,9 +32,11 @@ public class SetRank extends RCONMessage<SetRank.JSONSetRank> {
|
|||||||
|
|
||||||
static class JSONSetRank {
|
static class JSONSetRank {
|
||||||
|
|
||||||
|
@Positive(message = "invalid user")
|
||||||
public int user_id;
|
public int user_id;
|
||||||
|
|
||||||
|
|
||||||
|
@Positive(message = "invalid rank")
|
||||||
public int rank;
|
public int rank;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,7 +119,10 @@ public class RCONServer extends Server {
|
|||||||
try {
|
try {
|
||||||
RCONMessage rcon = message.getDeclaredConstructor().newInstance();
|
RCONMessage rcon = message.getDeclaredConstructor().newInstance();
|
||||||
Gson gson = this.gsonBuilder.create();
|
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());
|
LOGGER.info("Handled RCON Message: {}", message.getSimpleName());
|
||||||
result = gson.toJson(rcon, RCONMessage.class);
|
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