Compare commits

..
9 Commits
Author SHA1 Message Date
Jones 7f604dd4ad Release 2.0.5 (#74) 2023-10-20 17:41:16 +02:00
Jones ab96929070 Fix EmptyChunkData packet being broken on 1.17+ (#73) 2023-10-20 17:36:43 +02:00
Michel Elkenwaat fa20826b8e Merge remote-tracking branch 'origin/main' 2023-10-20 17:22:25 +02:00
Michel Elkenwaat c8c212a3ee Fix issues with the plugin description (#69) 2023-10-20 17:22:08 +02:00
Michel Elkenwaat ad7d3e62eb Fix issues with the plugin description https://github.com/jonesdevelopment/sonar/pull/69 2023-10-20 17:21:30 +02:00
Ismael 343d71d18c Fix incompatibilities with Gradle 7.x (#69)
Fix "java.lang.IllegalStateException: Module entity with name: sonar.bukkit should be available"
2023-10-20 16:38:52 +02:00
Jones a2e252aece Use a better conversion technique to improve update checker (#72) 2023-10-20 15:09:31 +02:00
Jones 124bed86dc Fix invalid root tag in chunk data packet (#70)
* fix: use Velocity's JoinGame packet for consistency (https://github.com/jonesdevelopment/sonar/issues/68)

* fix: incorrect motion blocking root tag in EmptyChunkData packet (https://github.com/jonesdevelopment/sonar/issues/68)
2023-10-20 14:19:53 +02:00
Jones 971d43df00 Recode IPv4 regex pattern check (#67) 2023-10-19 17:03:52 +02:00
13 changed files with 173 additions and 152 deletions

No files matched your search

+1 -1
View File
@@ -72,7 +72,7 @@ tasks {
shadowJar {
// Set the file name of the shadowed jar
archiveFileName.set("${rootProject.name}.jar")
archiveFileName.set("Sonar.jar")
// bStats has to be relocated to the Sonar package otherwise it throws an exception
// https://github.com/Bastian/bstats-metrics/blob/master/base/src/main/java/org/bstats/MetricsBase.java#L251
+2 -1
View File
@@ -1,2 +1,3 @@
group=xyz.jonesdev.sonar
version=2.0.4
version=2.0.5
description=Effective Anti-bot plugin for Velocity, BungeeCord, and Bukkit (1.7-latest)
+1 -1
View File
@@ -1,4 +1,4 @@
rootProject.name = "Sonar"
rootProject.name = "sonar"
sequenceOf("api", "bukkit", "bungee", "common", "velocity").forEach {
val path = "sonar-$it"
@@ -28,6 +28,7 @@ import xyz.jonesdev.sonar.api.command.subcommand.argument.Argument;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -35,10 +36,8 @@ import java.util.stream.Collectors;
public abstract class Subcommand {
private final @NotNull SubcommandInfo info;
private final String permission, aliases, arguments;
protected static final Sonar SONAR = Sonar.get();
protected static final Pattern IP_PATTERN = Pattern.compile(
"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])([.])){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
);
public Subcommand() {
info = getClass().getAnnotation(SubcommandInfo.class);
@@ -52,8 +51,14 @@ public abstract class Subcommand {
.collect(Collectors.joining(", "));
}
protected static @Nullable InetAddress checkIP(final InvocationSource source, final String rawIP) {
if (!IP_PATTERN.matcher(rawIP).matches()) {
// https://stackoverflow.com/questions/5284147/validating-ipv4-addresses-with-regexp
private static final Pattern IP_PATTERN = Pattern.compile("^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$");
protected static @Nullable InetAddress getInetAddressIfValid(final InvocationSource source, final String rawIP) {
// We perform a regex check beforehand,
// so we don't have to create a new InetAddress,
// therefore, potentially saving some performance.
if (!IP_PATTERN.matcher(Objects.requireNonNull(rawIP)).matches()) {
source.sendMessage(SONAR.getConfig().getCommands().getIncorrectIpAddress());
return null;
}
+1 -2
View File
@@ -7,12 +7,11 @@ plugins {
apply(plugin = "net.minecrell.plugin-yml.bukkit")
bukkit {
name = rootProject.name
name = "Sonar"
version = rootProject.version.toString().split("-")[0]
main = "xyz.jonesdev.sonar.bukkit.SonarBukkitPlugin"
authors = listOf("Jones Development", "Sonar Contributors")
website = "https://jonesdev.xyz/discord/"
description = "Effective Anti-bot plugin for Velocity, BungeeCord, and Bukkit (1.7-latest)"
load = BukkitPluginDescription.PluginLoadOrder.POSTWORLD
commands {
+1 -2
View File
@@ -5,11 +5,10 @@ plugins {
apply(plugin = "net.minecrell.plugin-yml.bungee")
bungee {
name = rootProject.name
name = "Sonar"
version = rootProject.version.toString().split("-")[0]
main = "xyz.jonesdev.sonar.bungee.SonarBungeePlugin"
author = "Jones Development, Sonar Contributors"
description = "Effective Anti-bot plugin for Velocity, BungeeCord, and Bukkit (1.7-latest)"
}
dependencies {
@@ -34,9 +34,9 @@ import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.writeCompo
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
@Getter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@ToString(of = {"x", "z"})
public final class EmptyChunkData implements FallbackPacket {
private int x, z;
@@ -56,10 +56,14 @@ public final class EmptyChunkData implements FallbackPacket {
}
private static @NotNull CompoundBinaryTag prepareNBT(final boolean legacy) {
final long[] arrayData = new long[legacy ? 36 : 37];
final LongArrayBinaryTag longArray = LongArrayBinaryTag.longArrayBinaryTag(arrayData);
final CompoundBinaryTag motion = CompoundBinaryTag.builder()
.put("MOTION_BLOCKING", longArray)
.build();
return CompoundBinaryTag.builder()
.put("root", CompoundBinaryTag.builder()
.put("MOTION_BLOCKING", LongArrayBinaryTag.longArrayBinaryTag(new long[legacy ? 36 : 37]))
.build())
.put("root", motion)
.build();
}
@@ -68,9 +72,10 @@ public final class EmptyChunkData implements FallbackPacket {
byteBuf.writeInt(x);
byteBuf.writeInt(z);
if (protocolVersion.compareTo(MINECRAFT_1_17) >= 0
&& protocolVersion.compareTo(MINECRAFT_1_17_1) <= 0) {
writeVarInt(byteBuf, 0); // mask
if (protocolVersion.compareTo(MINECRAFT_1_17) >= 0) {
if (protocolVersion.compareTo(MINECRAFT_1_17_1) <= 0) {
writeVarInt(byteBuf, 0); // mask
}
} else {
byteBuf.writeBoolean(true); // full chunk
@@ -22,12 +22,12 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
import xyz.jonesdev.sonar.common.fallback.protocol.dimension.DimensionInfo;
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.*;
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
@@ -57,135 +57,133 @@ public final class JoinGame implements FallbackPacket {
// https://github.com/Nan1t/NanoLimbo/blob/main/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketJoinGame.java
@Override
public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_20_2) >= 0) {
// haha funny, they made 1.20.2 more complicated
encode1202Up(byteBuf, protocolVersion);
} else if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
// Minecraft 1.16 and above have significantly more complicated logic for reading this packet,
// so separate it out.
encode116Up(byteBuf, protocolVersion);
} else {
encodeLegacy(byteBuf, protocolVersion);
}
}
private void encodeLegacy(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
byteBuf.writeInt(entityId);
if (protocolVersion.compareTo(MINECRAFT_1_9) <= 0) {
byteBuf.writeByte(gamemode);
byteBuf.writeByte(dimension);
byteBuf.writeByte(0); // difficulty
byteBuf.writeByte(1); // max players
writeString(byteBuf, "flat"); // level type
if (protocolVersion.compareTo(MINECRAFT_1_8) >= 0) {
byteBuf.writeBoolean(reducedDebugInfo);
}
}
if (protocolVersion.compareTo(MINECRAFT_1_9_1) >= 0
&& protocolVersion.compareTo(MINECRAFT_1_13_2) <= 0) {
byteBuf.writeByte(gamemode);
byteBuf.writeInt(dimension);
byteBuf.writeByte(0); // difficulty
byteBuf.writeByte(1); // max players
writeString(byteBuf, "flat"); // level type
byteBuf.writeBoolean(reducedDebugInfo);
}
if (protocolVersion.compareTo(MINECRAFT_1_14) >= 0
&& protocolVersion.compareTo(MINECRAFT_1_14_4) <= 0) {
byteBuf.writeByte(gamemode);
byteBuf.writeInt(dimension);
byteBuf.writeByte(1); // max players
writeString(byteBuf, "flat"); // level type
writeVarInt(byteBuf, viewDistance);
byteBuf.writeBoolean(reducedDebugInfo);
}
if (protocolVersion.compareTo(MINECRAFT_1_15) >= 0
&& protocolVersion.compareTo(MINECRAFT_1_15_2) <= 0) {
byteBuf.writeByte(gamemode);
byteBuf.writeInt(dimension);
byteBuf.writeLong(partialHashedSeed);
byteBuf.writeByte(1); // max players
writeString(byteBuf, "flat"); // level type
writeVarInt(byteBuf, viewDistance);
byteBuf.writeBoolean(reducedDebugInfo);
byteBuf.writeBoolean(showRespawnScreen);
}
if (protocolVersion.compareTo(MINECRAFT_1_16) >= 0
&& protocolVersion.compareTo(MINECRAFT_1_16_1) <= 0) {
byteBuf.writeByte(gamemode);
byteBuf.writeByte(previousGamemode);
writeStringArray(byteBuf, levelNames);
writeCompoundTag(byteBuf, registry);
writeString(byteBuf, dimensionInfo.getIdentifier());
writeString(byteBuf, dimensionInfo.getLevelName());
byteBuf.writeLong(partialHashedSeed);
byteBuf.writeByte(1); // max players
writeVarInt(byteBuf, viewDistance);
byteBuf.writeBoolean(reducedDebugInfo);
byteBuf.writeBoolean(showRespawnScreen);
byteBuf.writeBoolean(dimensionInfo.isDebug());
byteBuf.writeBoolean(dimensionInfo.isFlat());
}
if (protocolVersion.compareTo(MINECRAFT_1_16_2) >= 0
&& protocolVersion.compareTo(MINECRAFT_1_18_2) <= 0) {
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
byteBuf.writeBoolean(isHardcore);
byteBuf.writeByte(gamemode);
byteBuf.writeByte(previousGamemode);
writeStringArray(byteBuf, levelNames);
writeCompoundTag(byteBuf, registry);
} else {
byteBuf.writeByte(isHardcore ? gamemode | 0x8 : gamemode);
}
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_9_1) >= 0) {
byteBuf.writeInt(dimension);
} else {
byteBuf.writeByte(dimension);
}
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_13_2) <= 0) {
byteBuf.writeByte(difficulty);
}
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
byteBuf.writeLong(partialHashedSeed);
}
byteBuf.writeByte(1); // max players
if (levelType == null) {
throw new IllegalStateException("No level type specified.");
}
writeString(byteBuf, levelType);
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_14) >= 0) {
writeVarInt(byteBuf, viewDistance);
}
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
byteBuf.writeBoolean(reducedDebugInfo);
}
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_15) >= 0) {
byteBuf.writeBoolean(showRespawnScreen);
}
}
private void encode116Up(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
byteBuf.writeInt(entityId);
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
byteBuf.writeBoolean(isHardcore);
byteBuf.writeByte(gamemode);
} else {
byteBuf.writeByte(isHardcore ? gamemode | 0x8 : gamemode);
}
byteBuf.writeByte(previousGamemode);
writeStringArray(byteBuf, levelNames);
writeCompoundTag(byteBuf, registry);
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0
&& protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_19) < 0) {
writeCompoundTag(byteBuf, currentDimensionData);
writeString(byteBuf, dimensionInfo.getIdentifier());
byteBuf.writeLong(partialHashedSeed);
writeVarInt(byteBuf, 1); // max players
writeVarInt(byteBuf, viewDistance);
if (protocolVersion.compareTo(MINECRAFT_1_18) >= 0) {
writeVarInt(byteBuf, viewDistance); // simulation distance
}
byteBuf.writeBoolean(reducedDebugInfo);
byteBuf.writeBoolean(showRespawnScreen);
byteBuf.writeBoolean(dimensionInfo.isDebug());
byteBuf.writeBoolean(dimensionInfo.isFlat());
}
if (protocolVersion.compareTo(MINECRAFT_1_19) >= 0
&& protocolVersion.compareTo(MINECRAFT_1_20) <= 0) {
byteBuf.writeBoolean(isHardcore);
byteBuf.writeByte(gamemode);
byteBuf.writeByte(previousGamemode);
writeStringArray(byteBuf, levelNames);
writeCompoundTag(byteBuf, registry);
} else {
writeString(byteBuf, dimensionInfo.getIdentifier());
writeString(byteBuf, dimensionInfo.getLevelName());
byteBuf.writeLong(partialHashedSeed);
writeVarInt(byteBuf, 1); // max players
writeVarInt(byteBuf, viewDistance);
writeVarInt(byteBuf, viewDistance); // simulation distance
byteBuf.writeBoolean(reducedDebugInfo);
byteBuf.writeBoolean(showRespawnScreen);
byteBuf.writeBoolean(dimensionInfo.isDebug());
byteBuf.writeBoolean(dimensionInfo.isFlat());
byteBuf.writeBoolean(false); // last death location
if (protocolVersion.compareTo(MINECRAFT_1_20) == 0) {
writeVarInt(byteBuf, 0); // portal cooldown
}
}
if (protocolVersion.compareTo(MINECRAFT_1_20_2) >= 0) {
byteBuf.writeBoolean(isHardcore);
writeStringArray(byteBuf, levelNames);
writeVarInt(byteBuf, 1); // max players
writeVarInt(byteBuf, viewDistance);
writeVarInt(byteBuf, viewDistance); // simulation distance
byteBuf.writeBoolean(reducedDebugInfo);
byteBuf.writeBoolean(showRespawnScreen);
byteBuf.writeBoolean(limitedCrafting);
writeString(byteBuf, dimensionInfo.getIdentifier());
writeString(byteBuf, dimensionInfo.getLevelName());
byteBuf.writeLong(partialHashedSeed);
byteBuf.writeByte(gamemode);
byteBuf.writeByte(previousGamemode);
byteBuf.writeBoolean(dimensionInfo.isDebug());
byteBuf.writeBoolean(dimensionInfo.isFlat());
byteBuf.writeBoolean(false); // last death location
byteBuf.writeLong(partialHashedSeed);
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) {
writeVarInt(byteBuf, 0); // max players
} else {
byteBuf.writeByte(0); // max players
}
writeVarInt(byteBuf, viewDistance);
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_18) >= 0) {
writeVarInt(byteBuf, simulationDistance);
}
byteBuf.writeBoolean(reducedDebugInfo);
byteBuf.writeBoolean(showRespawnScreen);
byteBuf.writeBoolean(dimensionInfo.isDebug());
byteBuf.writeBoolean(dimensionInfo.isFlat());
// optional death location
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_19) >= 0) {
byteBuf.writeBoolean(false); // no last death position
}
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_20) >= 0) {
writeVarInt(byteBuf, 0); // portal cooldown
}
}
private void encode1202Up(final @NotNull ByteBuf byteBuf,
final @SuppressWarnings("unused") ProtocolVersion protocolVersion) {
byteBuf.writeInt(entityId);
byteBuf.writeBoolean(isHardcore);
writeStringArray(byteBuf, levelNames);
writeVarInt(byteBuf, 1); // max players
writeVarInt(byteBuf, viewDistance);
writeVarInt(byteBuf, simulationDistance);
byteBuf.writeBoolean(reducedDebugInfo);
byteBuf.writeBoolean(showRespawnScreen);
byteBuf.writeBoolean(limitedCrafting);
writeString(byteBuf, dimensionInfo.getIdentifier());
writeString(byteBuf, dimensionInfo.getLevelName());
byteBuf.writeLong(partialHashedSeed);
byteBuf.writeByte(gamemode);
byteBuf.writeByte(previousGamemode);
byteBuf.writeBoolean(dimensionInfo.isDebug());
byteBuf.writeBoolean(dimensionInfo.isFlat());
byteBuf.writeBoolean(false); // no last death position
writeVarInt(byteBuf, 0); // portal cooldown
}
@Override
public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
throw new UnsupportedOperationException();
@@ -49,7 +49,7 @@ public final class BlacklistCommand extends Subcommand {
}
final String rawInetAddress = invocation.getRawArguments()[2];
final InetAddress inetAddress = checkIP(invocation.getSender(), rawInetAddress);
final InetAddress inetAddress = getInetAddressIfValid(invocation.getSender(), rawInetAddress);
// Make sure the given IP address is valid
if (inetAddress == null) return;
@@ -80,7 +80,7 @@ public final class BlacklistCommand extends Subcommand {
}
final String rawInetAddress = invocation.getRawArguments()[2];
final InetAddress inetAddress = checkIP(invocation.getSender(), rawInetAddress);
final InetAddress inetAddress = getInetAddressIfValid(invocation.getSender(), rawInetAddress);
// Make sure the given IP address is valid
if (inetAddress == null) return;
@@ -53,7 +53,7 @@ public final class VerifiedCommand extends Subcommand {
}
final String rawInetAddress = invocation.getRawArguments()[2];
final InetAddress inetAddress = checkIP(invocation.getSender(), rawInetAddress);
final InetAddress inetAddress = getInetAddressIfValid(invocation.getSender(), rawInetAddress);
// Make sure the given IP address is valid
if (inetAddress == null) return;
@@ -85,7 +85,7 @@ public final class VerifiedCommand extends Subcommand {
return;
}
final InetAddress inetAddress = checkIP(invocation.getSender(), rawInetAddress);
final InetAddress inetAddress = getInetAddressIfValid(invocation.getSender(), rawInetAddress);
// Make sure the given IP address is valid
if (inetAddress == null) return;
@@ -38,24 +38,39 @@ public class UpdateChecker {
}
};
private int convertVersion(final @NotNull String version) throws NumberFormatException, IllegalStateException {
final String[] convertedParts = version.split("\\.");
// Validate the length of the converted parts
if (convertedParts.length != 3) {
throw new IllegalStateException("Converted version length mismatch");
}
// Major updates are more important than minor updates,
// and minor updates are more important than patches.
final int convertedMajor = Integer.parseInt(convertedParts[0]) * 100000; // multiply by weight
final int convertedMinor = Integer.parseInt(convertedParts[1]) * 10000; // multiply by weight
final int patch = Integer.parseInt(convertedParts[2]);
return convertedMajor + convertedMinor + patch; // sum the converted version parts
}
public void checkForUpdates() {
ASYNC_EXECUTOR.execute(() -> {
try {
final URL url = new URL("https://api.github.com/repos/jonesdevelopment/sonar/releases/latest");
final HttpsURLConnection urlConnection = prepareConnection(url);
final JsonObject json = parseJson(urlConnection.getInputStream());
final String latestStableVersion = json.get("tag_name").getAsString();
final String latestStableRelease = json.get("tag_name").getAsString();
final int convertedLatestVersion = convertVersion(latestStableRelease);
final int convertedCurrentVersion = convertVersion(Sonar.get().getVersion().getSemanticVersion());
if (!latestStableVersion.equals(Sonar.get().getVersion().getSemanticVersion())) {
LOGGER.warn("A new version of Sonar is available: {}", latestStableVersion);
if (convertedCurrentVersion < convertedLatestVersion) {
LOGGER.warn("A new version of Sonar is available: {}", latestStableRelease);
LOGGER.warn("Please make sure to update to the latest version to ensure stability and security:");
LOGGER.warn("https://github.com/jonesdevelopment/sonar/releases");
} else if (Sonar.get().getVersion().isOnMainBranch()) {
LOGGER.info("You are currently using the latest stable release of Sonar!");
LOGGER.warn("https://github.com/jonesdevelopment/sonar/releases/tag/{}", latestStableRelease);
} else if (convertedCurrentVersion > convertedLatestVersion || !Sonar.get().getVersion().isOnMainBranch()) {
LOGGER.warn("You are currently using an unreleased version of Sonar!");
LOGGER.warn("The contributors of Sonar are not responsible for any damage done by using an unstable version");
} else {
LOGGER.warn("You are currently using the latest development version of Sonar!");
LOGGER.warn("The contributors of Sonar are not responsible for any damage done by using an unstable version" +
".");
LOGGER.info("You are currently using the latest stable release of Sonar!");
}
} catch (Exception exception) {
LOGGER.warn("Could not retrieve latest version information: {}", exception);
+1 -2
View File
@@ -20,9 +20,8 @@ dependencies {
tasks {
processResources {
val props = mapOf(
"name" to rootProject.name,
"version" to rootProject.version.toString().split("-")[0],
"description" to "Effective Anti-bot plugin for Velocity, BungeeCord, and Bukkit (1.7-latest)",
"description" to rootProject.description,
"url" to "https://jonesdev.xyz/discord/",
"main" to "xyz.jonesdev.sonar.velocity.SonarVelocityPlugin"
)
@@ -1,6 +1,6 @@
{
"id": "sonar",
"name": "$name",
"name": "Sonar",
"version": "$version",
"description": "$description",
"url": "$url",