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 social and room commands
This commit is contained in:
@@ -3,6 +3,9 @@ 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.NotBlank;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
public class AlertUser extends RCONMessage<AlertUser.JSONAlertUser> {
|
||||
|
||||
@@ -16,6 +19,7 @@ public class AlertUser extends RCONMessage<AlertUser.JSONAlertUser> {
|
||||
|
||||
if (habbo != null) {
|
||||
habbo.alert(object.message);
|
||||
return;
|
||||
}
|
||||
|
||||
this.status = RCONMessage.HABBO_NOT_FOUND;
|
||||
@@ -23,9 +27,12 @@ public class AlertUser extends RCONMessage<AlertUser.JSONAlertUser> {
|
||||
|
||||
static class JSONAlertUser {
|
||||
|
||||
@Positive(message = "invalid user")
|
||||
int user_id;
|
||||
|
||||
|
||||
@NotBlank(message = "invalid message")
|
||||
@Size(max = 4096, message = "invalid message")
|
||||
String message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.messages.outgoing.rooms.ForwardToRoomComposer;
|
||||
import com.google.gson.Gson;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
|
||||
public class ForwardUser extends RCONMessage<ForwardUser.ForwardUserJSON> {
|
||||
|
||||
@@ -26,8 +27,10 @@ public class ForwardUser extends RCONMessage<ForwardUser.ForwardUserJSON> {
|
||||
|
||||
habbo.getClient().sendResponse(new ForwardToRoomComposer(object.room_id));
|
||||
Emulator.getGameEnvironment().getRoomManager().enterRoom(habbo, object.room_id, "", true);
|
||||
return;
|
||||
} else {
|
||||
this.status = RCONMessage.ROOM_NOT_FOUND;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,9 +39,11 @@ public class ForwardUser extends RCONMessage<ForwardUser.ForwardUserJSON> {
|
||||
|
||||
static class ForwardUserJSON {
|
||||
|
||||
@Positive(message = "invalid user")
|
||||
public int user_id;
|
||||
|
||||
|
||||
@Positive(message = "invalid room")
|
||||
public int room_id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.eu.habbo.messages.outgoing.MessageComposer;
|
||||
import com.eu.habbo.messages.outgoing.Outgoing;
|
||||
import com.eu.habbo.messages.outgoing.friends.FriendRequestComposer;
|
||||
import com.google.gson.Gson;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
|
||||
public class FriendRequest extends RCONMessage<FriendRequest.JSON> {
|
||||
public FriendRequest() {
|
||||
@@ -18,6 +19,18 @@ public class FriendRequest extends RCONMessage<FriendRequest.JSON> {
|
||||
|
||||
@Override
|
||||
public void handle(Gson gson, JSON json) {
|
||||
if (json.user_id == json.target_id) {
|
||||
this.status = RCONMessage.STATUS_ERROR;
|
||||
this.message = "cannot friend self";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!RconUserLookup.userExists(json.user_id) || !RconUserLookup.userExists(json.target_id)) {
|
||||
this.status = RCONMessage.HABBO_NOT_FOUND;
|
||||
this.message = "user not found";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Messenger.friendRequested(json.user_id, json.target_id)) {
|
||||
Messenger.makeFriendRequest(json.user_id, json.target_id);
|
||||
|
||||
@@ -49,9 +62,11 @@ public class FriendRequest extends RCONMessage<FriendRequest.JSON> {
|
||||
|
||||
static class JSON {
|
||||
|
||||
@Positive(message = "invalid user")
|
||||
public int user_id;
|
||||
|
||||
|
||||
@Positive(message = "invalid target")
|
||||
public int target_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -19,13 +20,25 @@ public class IgnoreUser extends RCONMessage<IgnoreUser.JSONIgnoreUser> {
|
||||
|
||||
@Override
|
||||
public void handle(Gson gson, JSONIgnoreUser object) {
|
||||
if (object.user_id == object.target_id) {
|
||||
this.status = RCONMessage.STATUS_ERROR;
|
||||
this.message = "cannot ignore self";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!RconUserLookup.userExists(object.user_id) || !RconUserLookup.userExists(object.target_id)) {
|
||||
this.status = RCONMessage.HABBO_NOT_FOUND;
|
||||
this.message = "user not found";
|
||||
return;
|
||||
}
|
||||
|
||||
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(object.user_id);
|
||||
|
||||
if (habbo != null) {
|
||||
habbo.getHabboStats().ignoreUser(habbo.getClient(), object.target_id);
|
||||
} else {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("INSERT INTO users_ignored (user_id, target_id) VALUES (?, ?)")) {
|
||||
PreparedStatement statement = connection.prepareStatement("INSERT IGNORE INTO users_ignored (user_id, target_id) VALUES (?, ?)")) {
|
||||
statement.setInt(1, object.user_id);
|
||||
statement.setInt(2, object.target_id);
|
||||
statement.execute();
|
||||
@@ -39,8 +52,10 @@ public class IgnoreUser extends RCONMessage<IgnoreUser.JSONIgnoreUser> {
|
||||
|
||||
static class JSONIgnoreUser {
|
||||
|
||||
@Positive(message = "invalid user")
|
||||
public int user_id;
|
||||
|
||||
@Positive(message = "invalid target")
|
||||
public int target_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.messages.outgoing.rooms.ForwardToRoomComposer;
|
||||
import com.google.gson.Gson;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
|
||||
public class StalkUser extends RCONMessage<StalkUser.StalkUserJSON> {
|
||||
public StalkUser() {
|
||||
@@ -44,14 +45,19 @@ public class StalkUser extends RCONMessage<StalkUser.StalkUserJSON> {
|
||||
if (this.status == 0) {
|
||||
habbo.getClient().sendResponse(new ForwardToRoomComposer(target.getHabboInfo().getCurrentRoom().getId()));
|
||||
}
|
||||
} else {
|
||||
this.status = HABBO_NOT_FOUND;
|
||||
this.message = "offline";
|
||||
}
|
||||
}
|
||||
|
||||
static class StalkUserJSON {
|
||||
|
||||
@Positive(message = "invalid user")
|
||||
public int user_id;
|
||||
|
||||
|
||||
@Positive(message = "invalid target")
|
||||
public int follow_id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomChatMessageBubbles;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.google.gson.Gson;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
public class TalkUser extends RCONMessage<TalkUser.JSON> {
|
||||
public TalkUser() {
|
||||
@@ -38,15 +41,20 @@ public class TalkUser extends RCONMessage<TalkUser.JSON> {
|
||||
|
||||
static class JSON {
|
||||
|
||||
@NotBlank(message = "invalid type")
|
||||
@Size(max = 16, message = "invalid type")
|
||||
public String type;
|
||||
|
||||
|
||||
@Positive(message = "invalid user")
|
||||
public int user_id;
|
||||
|
||||
|
||||
public int bubble_id = -1;
|
||||
|
||||
|
||||
@NotBlank(message = "invalid message")
|
||||
@Size(max = 512, message = "invalid message")
|
||||
public String message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
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 SocialRoomCommandGuardTest {
|
||||
@Test
|
||||
void forwardUserDoesNotOverwriteSuccessfulStatusWithNotFound() throws Exception {
|
||||
String source = Files.readString(Path.of("src/main/java/com/eu/habbo/messages/rcon/ForwardUser.java"));
|
||||
|
||||
assertTrue(source.contains("enterRoom(habbo, object.room_id, \"\", true);") && source.contains("return;"),
|
||||
"ForwardUser must return after a successful room forward instead of falling through to HABBO_NOT_FOUND");
|
||||
assertTrue(source.contains("@Positive(message = \"invalid user\")"),
|
||||
"ForwardUser must reject invalid user ids before execution");
|
||||
assertTrue(source.contains("@Positive(message = \"invalid room\")"),
|
||||
"ForwardUser must reject invalid room ids before execution");
|
||||
}
|
||||
|
||||
@Test
|
||||
void alertUserOnlyReportsNotFoundWhenTargetIsMissing() throws Exception {
|
||||
String source = Files.readString(Path.of("src/main/java/com/eu/habbo/messages/rcon/AlertUser.java"));
|
||||
|
||||
assertTrue(source.contains("habbo.alert(object.message);") && source.contains("return;"),
|
||||
"AlertUser must return after delivering the alert");
|
||||
assertTrue(source.contains("@NotBlank(message = \"invalid message\")"),
|
||||
"AlertUser must reject blank alerts before execution");
|
||||
assertTrue(source.contains("@Size(max = 4096"),
|
||||
"AlertUser must bound alert payload size");
|
||||
}
|
||||
|
||||
@Test
|
||||
void friendAndIgnoreRequestsValidateBothUsers() throws Exception {
|
||||
String friend = Files.readString(Path.of("src/main/java/com/eu/habbo/messages/rcon/FriendRequest.java"));
|
||||
String ignore = Files.readString(Path.of("src/main/java/com/eu/habbo/messages/rcon/IgnoreUser.java"));
|
||||
|
||||
assertTrue(friend.contains("json.user_id == json.target_id"),
|
||||
"FriendRequest must reject self-friend requests");
|
||||
assertTrue(friend.contains("RconUserLookup.userExists(json.user_id)") && friend.contains("RconUserLookup.userExists(json.target_id)"),
|
||||
"FriendRequest must reject missing source or target users");
|
||||
assertTrue(ignore.contains("object.user_id == object.target_id"),
|
||||
"IgnoreUser must reject self-ignore requests");
|
||||
assertTrue(ignore.contains("RconUserLookup.userExists(object.user_id)") && ignore.contains("RconUserLookup.userExists(object.target_id)"),
|
||||
"IgnoreUser must reject missing source or target users");
|
||||
assertTrue(ignore.contains("INSERT IGNORE INTO users_ignored"),
|
||||
"IgnoreUser offline writes must avoid duplicate rows");
|
||||
}
|
||||
|
||||
@Test
|
||||
void talkAndStalkPayloadsAreValidated() throws Exception {
|
||||
String talk = Files.readString(Path.of("src/main/java/com/eu/habbo/messages/rcon/TalkUser.java"));
|
||||
String stalk = Files.readString(Path.of("src/main/java/com/eu/habbo/messages/rcon/StalkUser.java"));
|
||||
|
||||
assertTrue(talk.contains("@NotBlank(message = \"invalid type\")"),
|
||||
"TalkUser must reject blank talk types before execution");
|
||||
assertTrue(talk.contains("@Size(max = 512"),
|
||||
"TalkUser must bound impersonated chat message size");
|
||||
assertTrue(stalk.contains("@Positive(message = \"invalid target\")"),
|
||||
"StalkUser must reject invalid target ids before execution");
|
||||
assertTrue(stalk.contains("this.status = HABBO_NOT_FOUND"),
|
||||
"StalkUser must report missing source users");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user