You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-20 15:36:17 +00:00
fix(rcon): cap subscription duration changes
This commit is contained in:
@@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
public class ModifyUserSubscription extends RCONMessage<ModifyUserSubscription.JSON> {
|
public class ModifyUserSubscription extends RCONMessage<ModifyUserSubscription.JSON> {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ModifyUserSubscription.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(ModifyUserSubscription.class);
|
||||||
|
static final int DEFAULT_MAX_DURATION_SECONDS = 31_536_000;
|
||||||
|
|
||||||
public ModifyUserSubscription() {
|
public ModifyUserSubscription() {
|
||||||
super(ModifyUserSubscription.JSON.class);
|
super(ModifyUserSubscription.JSON.class);
|
||||||
@@ -38,10 +39,11 @@ public class ModifyUserSubscription extends RCONMessage<ModifyUserSubscription.J
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int maxDuration = parseMaxDuration(Emulator.getConfig().getValue("rcon.subscription.max_duration_seconds", String.valueOf(DEFAULT_MAX_DURATION_SECONDS)));
|
||||||
if (json.action.equalsIgnoreCase("add") || json.action.equalsIgnoreCase("+") || json.action.equalsIgnoreCase("a")) {
|
if (json.action.equalsIgnoreCase("add") || json.action.equalsIgnoreCase("+") || json.action.equalsIgnoreCase("a")) {
|
||||||
if (json.duration < 1) {
|
if (!isValidDuration(json.duration, maxDuration)) {
|
||||||
this.status = RCONMessage.STATUS_ERROR;
|
this.status = RCONMessage.STATUS_ERROR;
|
||||||
this.message = "duration must be > 0";
|
this.message = "duration must be between 1 and " + maxDuration + " seconds";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,13 +60,13 @@ public class ModifyUserSubscription extends RCONMessage<ModifyUserSubscription.J
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (json.duration != -1) {
|
if (json.duration != -1) {
|
||||||
if (json.duration < 1) {
|
if (!isValidDuration(json.duration, maxDuration)) {
|
||||||
this.status = RCONMessage.STATUS_ERROR;
|
this.status = RCONMessage.STATUS_ERROR;
|
||||||
this.message = "duration must be > 0 or -1 to remove all time";
|
this.message = "duration must be between 1 and " + maxDuration + " seconds, or -1 to remove all time";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
s.addDuration(-json.duration);
|
s.addDuration(-Math.min(json.duration, s.getRemaining()));
|
||||||
this.status = RCONMessage.STATUS_OK;
|
this.status = RCONMessage.STATUS_OK;
|
||||||
this.message = "Successfully removed %time% seconds from %subscription% on %user%".replace("%time%", json.duration + "").replace("%user%", habbo.getUsername()).replace("%subscription%", json.type);
|
this.message = "Successfully removed %time% seconds from %subscription% on %user%".replace("%time%", json.duration + "").replace("%user%", habbo.getUsername()).replace("%subscription%", json.type);
|
||||||
} else {
|
} else {
|
||||||
@@ -85,6 +87,22 @@ public class ModifyUserSubscription extends RCONMessage<ModifyUserSubscription.J
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isValidDuration(int duration, int maxDuration) {
|
||||||
|
return duration >= 1 && duration <= maxDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parseMaxDuration(String configured) {
|
||||||
|
try {
|
||||||
|
int parsed = Integer.parseInt(configured);
|
||||||
|
if (parsed > 0) {
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return DEFAULT_MAX_DURATION_SECONDS;
|
||||||
|
}
|
||||||
|
|
||||||
static class JSON {
|
static class JSON {
|
||||||
|
|
||||||
public int user_id;
|
public int user_id;
|
||||||
@@ -96,4 +114,4 @@ public class ModifyUserSubscription extends RCONMessage<ModifyUserSubscription.J
|
|||||||
public int duration = -1; // Time to add/remove in seconds. -1 means remove subscription entirely
|
public int duration = -1; // Time to add/remove in seconds. -1 means remove subscription entirely
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
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.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class ModifyUserSubscriptionGuardTest {
|
||||||
|
@Test
|
||||||
|
void validatesDurationAgainstConfiguredCeiling() {
|
||||||
|
assertTrue(ModifyUserSubscription.isValidDuration(1, 10));
|
||||||
|
assertTrue(ModifyUserSubscription.isValidDuration(10, 10));
|
||||||
|
assertFalse(ModifyUserSubscription.isValidDuration(0, 10));
|
||||||
|
assertFalse(ModifyUserSubscription.isValidDuration(-1, 10));
|
||||||
|
assertFalse(ModifyUserSubscription.isValidDuration(11, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parsesInvalidDurationCeilingsAsDefault() {
|
||||||
|
assertEquals(ModifyUserSubscription.DEFAULT_MAX_DURATION_SECONDS, ModifyUserSubscription.parseMaxDuration(null));
|
||||||
|
assertEquals(ModifyUserSubscription.DEFAULT_MAX_DURATION_SECONDS, ModifyUserSubscription.parseMaxDuration("0"));
|
||||||
|
assertEquals(60, ModifyUserSubscription.parseMaxDuration("60"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void clampsPartialRemovalToRemainingSubscriptionTime() throws Exception {
|
||||||
|
String source = Files.readString(Path.of("src/main/java/com/eu/habbo/messages/rcon/ModifyUserSubscription.java"));
|
||||||
|
|
||||||
|
assertTrue(source.contains("Math.min(json.duration, s.getRemaining())"),
|
||||||
|
"Partial subscription removal must not drive duration below the remaining time");
|
||||||
|
assertTrue(source.contains("rcon.subscription.max_duration_seconds"),
|
||||||
|
"RCON subscription duration ceiling must be configurable");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user