mirror of
https://github.com/jonesdevelopment/sonar.git
synced 2026-11-08 10:25:31 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0b14214ae | ||
|
|
3d96a32f81 | ||
|
|
de67ab12c2 | ||
|
|
adef9d9ccb | ||
|
|
71b40af656 | ||
|
|
3a79711a8b | ||
|
|
3094f12f84 | ||
|
|
a74c3da8d4 | ||
|
|
427768fc43 | ||
|
|
b0d7dfb735 | ||
|
|
ff9216c4cc | ||
|
|
43a1aa2ae8 | ||
|
|
f36a613124 | ||
|
|
3e193bddd7 | ||
|
|
66d0651d1e | ||
|
|
b21c4e8a9a | ||
|
|
b77e0c4806 | ||
|
|
cb76dfe06e | ||
|
|
d0a758473f | ||
|
|
e4dfab87da | ||
|
|
2fe3ab1d8d | ||
|
|
4483e52852 | ||
|
|
22b41151d6 | ||
|
|
e849060db1 | ||
|
|
59b338e775 | ||
|
|
e33ee1333a | ||
|
|
50e6b017f8 | ||
|
|
f25cc18cb9 |
No files matched your search
@@ -0,0 +1 @@
|
||||
patreon: jonesdev
|
||||
@@ -48,6 +48,11 @@ Sonar also protects against spambot attacks since it queues the incoming connect
|
||||
Sonar is unlikely to ever falsely prevent a player from joining the server since Minecraft uses the TCP protocol, which means that packets are always sent in the correct order. Therefore, lag or ping should not affect the bot check.
|
||||
If you or one of your players experiences a false positive, make sure to report it by opening a [GitHub issue](https://github.com/jonesdevelopment/sonar/issues/new/choose) or a ticket on the [Discord server](https://jonesdev.xyz/discord/).
|
||||
|
||||
## Sponsors
|
||||
Massive thanks to the sponsors of Sonar who help keep this project running:
|
||||
|
||||
<a href="https://github.com/Hydoxl"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/107579333?v=4&h=50&w=50&fit=cover&mask=circle&maxage=7d" alt="logo" align="center"></a>
|
||||
|
||||
## Building
|
||||
If you want to build your own version of Sonar, please take a look at the [Sonar building documentation](https://docs.jonesdev.xyz/development/building).
|
||||
<br>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) ${YEAR} Sonar Contributors
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,3 +14,4 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
@@ -14,6 +14,3 @@ tasks {
|
||||
archiveFileName = "sonar-api-${rootProject.version}.jar"
|
||||
}
|
||||
}
|
||||
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
java.targetCompatibility = JavaVersion.VERSION_11
|
||||
@@ -75,28 +75,23 @@ public interface Sonar {
|
||||
|
||||
void reload();
|
||||
|
||||
@NotNull
|
||||
default SonarVersion getVersion() {
|
||||
@NotNull default SonarVersion getVersion() {
|
||||
return SonarVersion.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
default SonarEventManager getEventManager() {
|
||||
@NotNull default SonarEventManager getEventManager() {
|
||||
return SonarEventManager.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
default AttackTracker getAttackTracker() {
|
||||
@NotNull default AttackTracker getAttackTracker() {
|
||||
return AttackTracker.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
default Fallback getFallback() {
|
||||
@NotNull default Fallback getFallback() {
|
||||
return Fallback.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static Sonar get() {
|
||||
@NotNull static Sonar get() {
|
||||
return SonarSupplier.sonar;
|
||||
}
|
||||
}
|
||||
@@ -220,16 +220,12 @@ public final class SonarConfiguration {
|
||||
webhook.content = webhookConfig.getString("webhook.content");
|
||||
webhook.footer.text = webhookConfig.getString("webhook.embed.footer.text");
|
||||
webhook.footer.iconUrl = webhookConfig.getString("webhook.embed.footer.icon-url");
|
||||
|
||||
final String realEmbedPath = "webhook.embed";
|
||||
final String embedPath = realEmbedPath + ".";
|
||||
|
||||
webhook.embed.title = webhookConfig.getString(embedPath + "title");
|
||||
webhook.embed.titleUrl = webhookConfig.getString(embedPath + "title-url");
|
||||
webhook.embed.description = String.join("\n", webhookConfig.getStringList(embedPath + "description"));
|
||||
webhook.embed.r = webhookConfig.getInt(embedPath + "color.red");
|
||||
webhook.embed.g = webhookConfig.getInt(embedPath + "color.green");
|
||||
webhook.embed.b = webhookConfig.getInt(embedPath + "color.blue");
|
||||
webhook.embed.title = webhookConfig.getString("webhook.embed.title");
|
||||
webhook.embed.titleUrl = webhookConfig.getString("webhook.embed.title-url");
|
||||
webhook.embed.description = String.join("\n", webhookConfig.getStringList("webhook.embed.description"));
|
||||
webhook.embed.r = webhookConfig.getInt("webhook.embed.color.red");
|
||||
webhook.embed.g = webhookConfig.getInt("webhook.embed.color.green");
|
||||
webhook.embed.b = webhookConfig.getInt("webhook.embed.color.blue");
|
||||
|
||||
if (!webhook.url.isEmpty()) {
|
||||
if (webhook.username.isEmpty()) {
|
||||
@@ -266,6 +262,7 @@ public final class SonarConfiguration {
|
||||
|
||||
tooManyOnlinePerIp = deserializeDisconnectMessage("too-many-online-per-ip");
|
||||
verification.currentlyPreparing = deserializeDisconnectMessage("verification.currently-preparing");
|
||||
verification.unsupportedVersion = deserializeDisconnectMessage("verification.unsupported-version");
|
||||
verification.tooFastReconnect = deserializeDisconnectMessage("verification.too-fast-reconnect");
|
||||
verification.alreadyVerifying = deserializeDisconnectMessage("verification.already-verifying");
|
||||
verification.alreadyQueued = deserializeDisconnectMessage("verification.already-queued");
|
||||
@@ -440,6 +437,7 @@ public final class SonarConfiguration {
|
||||
private Component blacklisted;
|
||||
private Component protocolBlacklisted;
|
||||
private Component currentlyPreparing;
|
||||
private Component unsupportedVersion;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@@ -460,7 +458,7 @@ public final class SonarConfiguration {
|
||||
Library.builder()
|
||||
.groupId("org{}mariadb{}jdbc")
|
||||
.artifactId("mariadb-java-client")
|
||||
.version("3.4.1")
|
||||
.version("3.5.1")
|
||||
.relocate("org{}mariadb", "xyz{}jonesdev{}sonar{}libs{}mariadb")
|
||||
.build()),
|
||||
H2("H2", "jdbc:h2:file:%s", new H2DatabaseTypeAdapter(),
|
||||
|
||||
@@ -27,23 +27,17 @@ import xyz.jonesdev.sonar.api.timer.SystemTimer;
|
||||
import java.net.InetAddress;
|
||||
|
||||
public interface FallbackUser {
|
||||
@NotNull
|
||||
Channel channel();
|
||||
@NotNull Channel channel();
|
||||
|
||||
@NotNull
|
||||
InetAddress getInetAddress();
|
||||
@NotNull InetAddress getInetAddress();
|
||||
|
||||
@NotNull
|
||||
ProtocolVersion getProtocolVersion();
|
||||
@NotNull ProtocolVersion getProtocolVersion();
|
||||
|
||||
@NotNull
|
||||
SystemTimer getLoginTimer();
|
||||
@NotNull SystemTimer getLoginTimer();
|
||||
|
||||
@NotNull
|
||||
String getFingerprint();
|
||||
@NotNull String getFingerprint();
|
||||
|
||||
@NotNull
|
||||
String getUsername();
|
||||
@NotNull String getUsername();
|
||||
|
||||
boolean isForceCaptcha();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Sonar Contributors
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -26,52 +26,53 @@ import java.util.Map;
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum ProtocolVersion {
|
||||
UNKNOWN(-1),
|
||||
MINECRAFT_1_7_2(4),
|
||||
MINECRAFT_1_7_6(5),
|
||||
MINECRAFT_1_8(47),
|
||||
MINECRAFT_1_9(107),
|
||||
MINECRAFT_1_9_1(108),
|
||||
MINECRAFT_1_9_2(109),
|
||||
MINECRAFT_1_9_4(110),
|
||||
MINECRAFT_1_10(210),
|
||||
MINECRAFT_1_11(315),
|
||||
MINECRAFT_1_11_1(316),
|
||||
MINECRAFT_1_12(335),
|
||||
MINECRAFT_1_12_1(338),
|
||||
MINECRAFT_1_12_2(340),
|
||||
MINECRAFT_1_13(393),
|
||||
MINECRAFT_1_13_1(401),
|
||||
MINECRAFT_1_13_2(404),
|
||||
MINECRAFT_1_14(477),
|
||||
MINECRAFT_1_14_1(480),
|
||||
MINECRAFT_1_14_2(485),
|
||||
MINECRAFT_1_14_3(490),
|
||||
MINECRAFT_1_14_4(498),
|
||||
MINECRAFT_1_15(573),
|
||||
MINECRAFT_1_15_1(575),
|
||||
MINECRAFT_1_15_2(578),
|
||||
MINECRAFT_1_16(735),
|
||||
MINECRAFT_1_16_1(736),
|
||||
MINECRAFT_1_16_2(751),
|
||||
MINECRAFT_1_16_3(753),
|
||||
MINECRAFT_1_16_4(754),
|
||||
MINECRAFT_1_17(755),
|
||||
MINECRAFT_1_17_1(756),
|
||||
MINECRAFT_1_18(757),
|
||||
MINECRAFT_1_18_2(758),
|
||||
MINECRAFT_1_19(759),
|
||||
MINECRAFT_1_19_1(760),
|
||||
MINECRAFT_1_19_3(761),
|
||||
MINECRAFT_1_19_4(762),
|
||||
MINECRAFT_1_20(763),
|
||||
MINECRAFT_1_20_2(764),
|
||||
MINECRAFT_1_20_3(765),
|
||||
MINECRAFT_1_20_5(766),
|
||||
MINECRAFT_1_21(767),
|
||||
MINECRAFT_1_21_2(768);
|
||||
UNKNOWN(-1, "Unknown"),
|
||||
MINECRAFT_1_7_2(4, "1.7.2"),
|
||||
MINECRAFT_1_7_6(5, "1.7.6"),
|
||||
MINECRAFT_1_8(47, "1.8"),
|
||||
MINECRAFT_1_9(107, "1.9"),
|
||||
MINECRAFT_1_9_1(108, "1.9.1"),
|
||||
MINECRAFT_1_9_2(109, "1.9.2"),
|
||||
MINECRAFT_1_9_4(110, "1.9.3"),
|
||||
MINECRAFT_1_10(210, "1.10"),
|
||||
MINECRAFT_1_11(315, "1.11"),
|
||||
MINECRAFT_1_11_1(316, "1.11.1"),
|
||||
MINECRAFT_1_12(335, "1.12"),
|
||||
MINECRAFT_1_12_1(338, "1.12.1"),
|
||||
MINECRAFT_1_12_2(340, "1.12.2"),
|
||||
MINECRAFT_1_13(393, "1.13"),
|
||||
MINECRAFT_1_13_1(401, "1.13.1"),
|
||||
MINECRAFT_1_13_2(404, "1.13.2"),
|
||||
MINECRAFT_1_14(477, "1.14"),
|
||||
MINECRAFT_1_14_1(480, "1.14.1"),
|
||||
MINECRAFT_1_14_2(485, "1.14.2"),
|
||||
MINECRAFT_1_14_3(490, "1.14.3"),
|
||||
MINECRAFT_1_14_4(498, "1.14.4"),
|
||||
MINECRAFT_1_15(573, "1.15"),
|
||||
MINECRAFT_1_15_1(575, "1.15.1"),
|
||||
MINECRAFT_1_15_2(578, "1.15.2"),
|
||||
MINECRAFT_1_16(735, "1.16"),
|
||||
MINECRAFT_1_16_1(736, "1.16.1"),
|
||||
MINECRAFT_1_16_2(751, "1.16.2"),
|
||||
MINECRAFT_1_16_3(753, "1.16.3"),
|
||||
MINECRAFT_1_16_4(754, "1.16.4"),
|
||||
MINECRAFT_1_17(755, "1.17"),
|
||||
MINECRAFT_1_17_1(756, "1.17.1"),
|
||||
MINECRAFT_1_18(757, "1.18"),
|
||||
MINECRAFT_1_18_2(758, "1.18.2"),
|
||||
MINECRAFT_1_19(759, "1.19"),
|
||||
MINECRAFT_1_19_1(760, "1.19.1"),
|
||||
MINECRAFT_1_19_3(761, "1.19.3"),
|
||||
MINECRAFT_1_19_4(762, "1.19.4"),
|
||||
MINECRAFT_1_20(763, "1.20"),
|
||||
MINECRAFT_1_20_2(764, "1.20.2"),
|
||||
MINECRAFT_1_20_3(765, "1.20.3"),
|
||||
MINECRAFT_1_20_5(766, "1.20.5"),
|
||||
MINECRAFT_1_21(767, "1.21"),
|
||||
MINECRAFT_1_21_2(768, "1.21.2");
|
||||
|
||||
private final int protocol;
|
||||
private final String name;
|
||||
|
||||
public static final ProtocolVersion LATEST_VERSION;
|
||||
public static final Map<Integer, ProtocolVersion> ID_TO_PROTOCOL_CONSTANT;
|
||||
|
||||
+18
-2
@@ -3,7 +3,8 @@ import net.kyori.indra.git.IndraGitExtension
|
||||
plugins {
|
||||
java
|
||||
alias(libs.plugins.shadow)
|
||||
alias(libs.plugins.indra.git) apply true
|
||||
alias(libs.plugins.indra.git)
|
||||
alias(libs.plugins.spotless)
|
||||
}
|
||||
|
||||
allprojects {
|
||||
@@ -15,6 +16,7 @@ allprojects {
|
||||
|
||||
apply(plugin = "java")
|
||||
apply(plugin = "com.gradleup.shadow")
|
||||
apply(plugin = "com.diffplug.spotless")
|
||||
|
||||
dependencies {
|
||||
compileOnly(rootProject.libs.lombok)
|
||||
@@ -31,6 +33,17 @@ allprojects {
|
||||
compileOnly(rootProject.libs.libby.core)
|
||||
}
|
||||
|
||||
spotless {
|
||||
java {
|
||||
endWithNewline()
|
||||
formatAnnotations()
|
||||
removeUnusedImports()
|
||||
trimTrailingWhitespace()
|
||||
indentWithSpaces(2)
|
||||
licenseHeaderFile("../HEADER")
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
shadowJar {
|
||||
// Set the file name of the shadowed jar
|
||||
@@ -80,6 +93,9 @@ allprojects {
|
||||
attributes["Git-Commit"] = gitCommit
|
||||
}
|
||||
}
|
||||
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
java.targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +103,7 @@ tasks {
|
||||
// This is a small wrapper tasks to simplify the building process
|
||||
register("build-sonar") {
|
||||
val subprojects = listOf("api", "captcha", "common", "bukkit", "bungeecord", "velocity")
|
||||
val buildTasks = subprojects.flatMap { listOf("$it:clean", "$it:shadowJar") }
|
||||
val buildTasks = subprojects.flatMap { listOf("$it:clean", "$it:spotlessApply", "$it:shadowJar") }
|
||||
dependsOn(buildTasks)
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,3 @@ tasks {
|
||||
relocate("net.kyori", "xyz.jonesdev.sonar.libs.kyori")
|
||||
}
|
||||
}
|
||||
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
java.targetCompatibility = JavaVersion.VERSION_11
|
||||
@@ -30,6 +30,3 @@ tasks {
|
||||
archiveFileName = "Sonar-Bungee.jar" // Hardcode a shortened version of the name
|
||||
}
|
||||
}
|
||||
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
java.targetCompatibility = JavaVersion.VERSION_11
|
||||
@@ -5,6 +5,3 @@ dependencies {
|
||||
testCompileOnly(project(":api"))
|
||||
testCompileOnly(rootProject.libs.imagefilters)
|
||||
}
|
||||
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
java.targetCompatibility = JavaVersion.VERSION_11
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Sonar Contributors
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -3,6 +3,3 @@ dependencies {
|
||||
implementation(project(":captcha"))
|
||||
compileOnly(rootProject.libs.adventure.nbt)
|
||||
}
|
||||
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
java.targetCompatibility = JavaVersion.VERSION_11
|
||||
@@ -83,8 +83,7 @@ public final class FallbackInboundHandler extends ChannelInboundHandlerAdapter {
|
||||
* will run before the connection knows that there has been an error.
|
||||
*/
|
||||
@Override
|
||||
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx,
|
||||
final Throwable cause) throws Exception {
|
||||
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final Throwable cause) throws Exception {
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
+14
-14
@@ -28,6 +28,7 @@ import xyz.jonesdev.sonar.api.fingerprint.FingerprintingUtil;
|
||||
import xyz.jonesdev.sonar.common.fallback.netty.FallbackTimeoutHandler;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketEncoder;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry;
|
||||
import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
|
||||
import xyz.jonesdev.sonar.common.util.GeyserUtil;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
@@ -73,17 +74,23 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
final @NotNull Runnable initialLoginAction,
|
||||
final @NotNull String username,
|
||||
final @NotNull InetSocketAddress socketAddress) throws Exception {
|
||||
// Check if the player has already sent a login packet
|
||||
if (this.username != null) {
|
||||
// Count every single attempted login
|
||||
GlobalSonarStatistics.countLogin();
|
||||
// Ensure that the player sent a handshake packet
|
||||
if (protocolVersion == null) {
|
||||
throw QuietDecoderException.INSTANCE;
|
||||
}
|
||||
// Connections from unknown protocol versions will be discarded
|
||||
// as this is the safest way of handling unwanted connections.
|
||||
// Sonar does not support snapshots or Minecraft versions older than 1.7.2
|
||||
if (protocolVersion.isUnknown()) {
|
||||
customDisconnect(ctx.channel(), unsupportedVersion, ProtocolVersion.MINECRAFT_1_7_2);
|
||||
return;
|
||||
}
|
||||
// Ensure that the player has not sent a login packet yet
|
||||
if (this.username != null) {
|
||||
throw QuietDecoderException.INSTANCE;
|
||||
}
|
||||
GlobalSonarStatistics.countLogin();
|
||||
this.username = username;
|
||||
|
||||
final InetAddress inetAddress = socketAddress.getAddress();
|
||||
@@ -150,17 +157,8 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
return null;
|
||||
}
|
||||
|
||||
return () -> {
|
||||
// Check if the username matches the valid name regex to prevent
|
||||
// UTF-16 names or other types of exploits
|
||||
if (!Sonar.get().getConfig().getVerification().getValidNameRegex().matcher(username).matches()) {
|
||||
customDisconnect(ctx.channel(), invalidUsername, protocolVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create an instance for the user and let the verification handler take over the channel
|
||||
new FallbackUserWrapper(ctx.channel(), inetAddress, protocolVersion, username, fingerprint, geyser);
|
||||
};
|
||||
// Create an instance for the user and let the verification handler take over the channel
|
||||
return () -> new FallbackUserWrapper(ctx, inetAddress, protocolVersion, username, fingerprint, geyser);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -231,6 +229,7 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
private static void _customDisconnect(final @NotNull Channel channel,
|
||||
final @NotNull FallbackPacket packet,
|
||||
final @NotNull ProtocolVersion protocolVersion) {
|
||||
// TODO: recode this
|
||||
// Remove the connection handler pipeline to completely take over the channel
|
||||
final String handler = Sonar.get().getPlatform().getConnectionHandler();
|
||||
if (channel.pipeline().context(handler) != null) {
|
||||
@@ -243,6 +242,7 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
// We don't need to update the encoder if it has already been replaced by Sonar
|
||||
if (!(currentEncoder instanceof FallbackPacketEncoder)) {
|
||||
final FallbackPacketEncoder newEncoder = new FallbackPacketEncoder(protocolVersion);
|
||||
newEncoder.updateRegistry(FallbackPacketRegistry.LOGIN);
|
||||
channel.pipeline().replace(encoder, FALLBACK_PACKET_ENCODER, newEncoder);
|
||||
}
|
||||
ProtocolUtil.closeWith(channel, protocolVersion, packet);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package xyz.jonesdev.sonar.common.fallback;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
@@ -59,13 +60,13 @@ public final class FallbackUserWrapper implements FallbackUser {
|
||||
@Setter
|
||||
private boolean forceCaptcha;
|
||||
|
||||
public FallbackUserWrapper(final @NotNull Channel channel,
|
||||
public FallbackUserWrapper(final @NotNull ChannelHandlerContext ctx,
|
||||
final @NotNull InetAddress inetAddress,
|
||||
final @NotNull ProtocolVersion protocolVersion,
|
||||
final @NotNull String username,
|
||||
final @NotNull String fingerprint,
|
||||
final boolean geyser) {
|
||||
this.channel = channel;
|
||||
this.channel = ctx.channel();
|
||||
this.inetAddress = inetAddress;
|
||||
this.protocolVersion = protocolVersion;
|
||||
this.username = username;
|
||||
@@ -82,7 +83,7 @@ public final class FallbackUserWrapper implements FallbackUser {
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("verification.logs.connection")
|
||||
.replace("<username>", username)
|
||||
.replace("<ip>", Sonar.get().getConfig().formatAddress(inetAddress))
|
||||
.replace("<protocol>", String.valueOf(protocolVersion.getProtocol())));
|
||||
.replace("<protocol>", protocolVersion.getName()));
|
||||
}
|
||||
|
||||
// Call the VerifyJoinEvent for external API usage
|
||||
|
||||
+1
-2
@@ -30,8 +30,7 @@ public final class FallbackTailExceptionsHandler extends ChannelDuplexHandler {
|
||||
// does not have any other pipelines that could handle this error.
|
||||
// Additionally, this will also run after our custom decoder.
|
||||
@Override
|
||||
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx,
|
||||
final Throwable cause) throws Exception {
|
||||
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final Throwable cause) throws Exception {
|
||||
// Close the channel if we encounter any errors.
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
+1
@@ -43,6 +43,7 @@ public final class FallbackVarInt21FrameDecoder extends ByteToMessageDecoder {
|
||||
// Skip any runs of 0x00 we might find
|
||||
final int packetStart = byteBuf.forEachByte(ByteProcessor.FIND_NON_NUL);
|
||||
if (packetStart == -1) {
|
||||
byteBuf.clear();
|
||||
return;
|
||||
}
|
||||
byteBuf.readerIndex(packetStart);
|
||||
|
||||
+2
@@ -422,6 +422,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x64, MINECRAFT_1_20_5, true),
|
||||
map(0x6B, MINECRAFT_1_21_2, true));
|
||||
|
||||
serverbound.register(ClientTickEndPacket.class, ClientTickEndPacket::new,
|
||||
map(0x0B, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(SetHeldItemPacket.class, SetHeldItemPacket::new,
|
||||
map(0x09, MINECRAFT_1_7_2, false),
|
||||
map(0x17, MINECRAFT_1_9, false),
|
||||
|
||||
+2
-2
@@ -111,7 +111,7 @@ public class FallbackPreparer {
|
||||
public FallbackPacket alreadyVerifying;
|
||||
public FallbackPacket reconnectedTooFast;
|
||||
public FallbackPacket protocolBlacklisted;
|
||||
public FallbackPacket invalidUsername;
|
||||
public FallbackPacket unsupportedVersion;
|
||||
public FallbackPacket tooManyOnlinePerIP;
|
||||
public FallbackPacket[] xpCountdown;
|
||||
public FallbackPacket updateTime;
|
||||
@@ -188,7 +188,7 @@ public class FallbackPreparer {
|
||||
alreadyQueued = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getAlreadyQueued(), true));
|
||||
protocolBlacklisted = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getProtocolBlacklisted(), true));
|
||||
reconnectedTooFast = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getTooFastReconnect(), true));
|
||||
invalidUsername = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getInvalidUsername(), true));
|
||||
unsupportedVersion = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getUnsupportedVersion(), true));
|
||||
tooManyOnlinePerIP = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getTooManyOnlinePerIp(), true));
|
||||
|
||||
// Prepare transfer packet
|
||||
|
||||
+4
-2
@@ -88,10 +88,12 @@ public final class ChunkDataPacket implements FallbackPacket {
|
||||
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
byteBuf.writeInt(0);
|
||||
byteBuf.writeBytes(new byte[2]);
|
||||
} else if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||
} else if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
||||
ProtocolUtil.writeVarInt(byteBuf, 0);
|
||||
} else if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_18)) {
|
||||
} else if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||
ProtocolUtil.writeByteArray(byteBuf, new byte[256 * 4]);
|
||||
} else if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_18)) {
|
||||
ProtocolUtil.writeVarInt(byteBuf, 0);
|
||||
} else {
|
||||
final byte[] sectionData = new byte[]{0, 0, 0, 0, 0, 0, 1, 0};
|
||||
int count = protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2) ? 24 : 16;
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
public final class ClientTickEndPacket implements FallbackPacket {
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int expectedMaxLength(final ProtocolVersion protocolVersion) {
|
||||
// This packet is always empty
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -41,7 +41,7 @@ public final class DisconnectPacket implements FallbackPacket {
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
// Force json serialization during login phase
|
||||
// Force JSON serialization during login phase
|
||||
componentHolder.write(byteBuf, protocolVersion, duringLogin);
|
||||
}
|
||||
|
||||
|
||||
+8
-1
@@ -91,7 +91,7 @@ public final class FallbackGravityHandler extends FallbackVerificationHandler {
|
||||
private final boolean enableGravityCheck, enableCollisionsCheck;
|
||||
private boolean teleported, canFall, checkMovement;
|
||||
private double y, deltaY, blockHeight;
|
||||
private int movementTick, expectedTeleportId = FIRST_TELEPORT_ID;
|
||||
private int movementTick, clientTick, expectedTeleportId = FIRST_TELEPORT_ID;
|
||||
private SetPlayerPositionRotationPacket lastPositionPacket;
|
||||
|
||||
@Override
|
||||
@@ -139,6 +139,8 @@ public final class FallbackGravityHandler extends FallbackVerificationHandler {
|
||||
// Pass these packets back to the login handler
|
||||
// TODO: recode this
|
||||
preJoinHandler.handle(packet);
|
||||
} else if (packet instanceof ClientTickEndPacket) {
|
||||
clientTick++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,6 +202,11 @@ public final class FallbackGravityHandler extends FallbackVerificationHandler {
|
||||
checkState(Math.abs(Math.abs(x) - BLOCKS_PER_ROW) < BLOCKS_PER_ROW, "illegal x offset: " + x);
|
||||
checkState(Math.abs(Math.abs(z) - BLOCKS_PER_ROW) < BLOCKS_PER_ROW, "illegal z offset: " + z);
|
||||
|
||||
// Check if the client is ticking correctly
|
||||
if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
checkState(clientTick >= movementTick, "invalid ticking: " + clientTick + "/" + movementTick);
|
||||
}
|
||||
|
||||
if (!onGround) {
|
||||
// The deltaY is 0 whenever the player sends their first position packet.
|
||||
// We have to account for this or the player will falsely fail the verification.
|
||||
|
||||
+5
@@ -157,6 +157,11 @@ public final class FallbackPreJoinHandler extends FallbackVerificationHandler {
|
||||
|
||||
private void markSuccess() {
|
||||
if (user.channel().isActive()) {
|
||||
if (!Sonar.get().getConfig().getVerification().getValidNameRegex().matcher(user.getUsername()).matches()) {
|
||||
user.disconnect(Sonar.get().getConfig().getVerification().getInvalidUsername());
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass the player to the next verification handler
|
||||
final FallbackGravityHandler gravityHandler = new FallbackGravityHandler(user, this);
|
||||
user.channel().pipeline().get(FallbackPacketDecoder.class).setListener(gravityHandler);
|
||||
|
||||
+2
-2
@@ -93,7 +93,7 @@ public abstract class FallbackVerificationHandler implements FallbackPacketListe
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("verification.logs.failed")
|
||||
.replace("<username>", user.getUsername())
|
||||
.replace("<ip>", Sonar.get().getConfig().formatAddress(user.getInetAddress()))
|
||||
.replace("<protocol>", String.valueOf(user.getProtocolVersion().getProtocol()))
|
||||
.replace("<protocol>", user.getProtocolVersion().getName())
|
||||
.replace("<reason>", reason));
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ public abstract class FallbackVerificationHandler implements FallbackPacketListe
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("verification.logs.blacklisted")
|
||||
.replace("<username>", user.getUsername())
|
||||
.replace("<ip>", Sonar.get().getConfig().formatAddress(user.getInetAddress()))
|
||||
.replace("<protocol>", String.valueOf(user.getProtocolVersion().getProtocol())));
|
||||
.replace("<protocol>", user.getProtocolVersion().getName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.google.gson.internal.LazilyParsedNumber;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.nbt.*;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
|
||||
@@ -36,9 +37,9 @@ public final class ComponentHolder {
|
||||
private final BinaryTag binaryTag;
|
||||
|
||||
public ComponentHolder(final @NotNull Component component) {
|
||||
this.modernJson = ProtocolUtil.PRE_1_20_3_SERIALIZER.serialize(component);
|
||||
this.legacyJson = ProtocolUtil.PRE_1_16_SERIALIZER.serialize(component);
|
||||
this.binaryTag = serialize(new JsonParser().parse(ProtocolUtil.MODERN_SERIALIZER.serialize(component)));
|
||||
this.modernJson = GsonComponentSerializer.gson().serialize(component);
|
||||
this.legacyJson = GsonComponentSerializer.colorDownsamplingGson().serialize(component);
|
||||
this.binaryTag = serialize(new JsonParser().parse(this.modernJson));
|
||||
}
|
||||
|
||||
// https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java
|
||||
|
||||
@@ -15,27 +15,6 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2021 Andrew Steinborn
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies
|
||||
* or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.util;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
@@ -50,9 +29,6 @@ import lombok.experimental.UtilityClass;
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.BinaryTagType;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.json.JSONOptions;
|
||||
import net.kyori.option.OptionState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.dimension.DimensionRegistry;
|
||||
@@ -66,41 +42,6 @@ import java.util.concurrent.TimeUnit;
|
||||
// https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java
|
||||
@UtilityClass
|
||||
public class ProtocolUtil {
|
||||
public static final GsonComponentSerializer PRE_1_16_SERIALIZER = GsonComponentSerializer.builder()
|
||||
.downsampleColors()
|
||||
.options(OptionState.optionState()
|
||||
// before 1.16
|
||||
.value(JSONOptions.EMIT_RGB, Boolean.FALSE)
|
||||
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.LEGACY_ONLY)
|
||||
// before 1.20.3
|
||||
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.FALSE)
|
||||
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.FALSE)
|
||||
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.FALSE)
|
||||
.build())
|
||||
.build();
|
||||
public static final GsonComponentSerializer PRE_1_20_3_SERIALIZER = GsonComponentSerializer.builder()
|
||||
.options(OptionState.optionState()
|
||||
// after 1.16
|
||||
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
|
||||
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.MODERN_ONLY)
|
||||
// before 1.20.3
|
||||
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.FALSE)
|
||||
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.FALSE)
|
||||
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.FALSE)
|
||||
.build())
|
||||
.build();
|
||||
public static final GsonComponentSerializer MODERN_SERIALIZER = GsonComponentSerializer.builder()
|
||||
.options(OptionState.optionState()
|
||||
// after 1.16
|
||||
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
|
||||
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.MODERN_ONLY)
|
||||
// after 1.20.3
|
||||
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.TRUE)
|
||||
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.TRUE)
|
||||
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.TRUE)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
public static final boolean DEBUG = Boolean.getBoolean("sonar.debug-traces");
|
||||
private static final int[] VAR_INT_LENGTHS = new int[65];
|
||||
|
||||
@@ -140,6 +81,27 @@ public class ProtocolUtil {
|
||||
throw DEBUG ? new DecoderException("Bad VarInt") : QuietDecoderException.INSTANCE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright 2021 Andrew Steinborn
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies
|
||||
* or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
public static void writeVarInt(final @NotNull ByteBuf byteBuf, final int value) {
|
||||
// Peel the one and two byte count cases explicitly as they are the most common VarInt sizes
|
||||
// that the proxy will write, to improve inlining.
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
# 需要帮助吗? https://jonesdev.xyz/discord
|
||||
# 源代码: https://github.com/jonesdevelopment/sonar
|
||||
# 文件: https://docs.jonesdev.xyz/administration/configuring-sonar
|
||||
# Copyright Jones Development and Sonar Contributors, 以 GPL-3.0 许可
|
||||
# Copyright Jones Development and Sonar Contributors, 以 GPL-3.0 许可证分发
|
||||
#
|
||||
|
||||
# 未归类的设置
|
||||
# 常规的设置
|
||||
general:
|
||||
# Sonar 是否应该自动检查新的更新?
|
||||
# Sonar 使用 GitHub API 检查当前版本是否过时
|
||||
@@ -24,18 +24,19 @@ general:
|
||||
# 具有相同 IP 地址的在线玩家的最大数量
|
||||
max-online-per-ip: 3
|
||||
|
||||
# 攻击检测器的敏感度设置
|
||||
# 只有当您知道自己在做什么的时候才编辑它
|
||||
# 攻击检测器
|
||||
# 只有当您知道自己在做什么的时候才应该编辑它
|
||||
attack-tracker:
|
||||
# 在一段时间内至少需要 x 个新玩家加入才满足触发条件.
|
||||
# 在一段时间内至少需要多少个新玩家加入才满足触发条件?
|
||||
min-players-for-attack: 8
|
||||
# 至少经过多少毫秒后才可以解除遭受攻击模式
|
||||
# (该值为毫秒. 1秒等于1000毫秒.)
|
||||
min-attack-duration: 30000
|
||||
# 攻击检测器要重复检测到多少次攻击 才能确认服务器正在遭受攻击?
|
||||
# 要重复检测到多少次攻击 才应该被确认为服务器正在遭受攻击?
|
||||
# 该值作为缓冲区 以避免可能的误判
|
||||
min-attack-threshold: 2
|
||||
# 当从遭受攻击标记为解除攻击时 应该需要等待多久才能再次被标记为正在遭受攻击?
|
||||
# 当从遭受攻击状态标记为已缓解攻击状态时
|
||||
# 至少需要多少毫秒才允许为对于可能检测到的攻击重新进入遭受攻击状态?
|
||||
# (该值为毫秒. 1秒等于1000毫秒.)
|
||||
attack-cooldown-delay: 3000
|
||||
|
||||
@@ -43,7 +44,7 @@ attack-tracker:
|
||||
# 提示: IP 地址将以纯文本形式保存 请确保您的数据库安全!
|
||||
database:
|
||||
# 要连接到的数据库类型
|
||||
# 可用类型: NONE (不使用数据库), MYSQL, MARIADB, H2
|
||||
# 可用类型: NONE (不使用数据库), MYSQL, MARIADB, H2 (本地数据库)
|
||||
type: NONE
|
||||
# Sonar 插件目录中用于 H2 数据库的文件
|
||||
filename: verified_players
|
||||
@@ -72,31 +73,31 @@ verification:
|
||||
# 可用类型: ALWAYS, DURING_ATTACK, NEVER
|
||||
# - ALWAYS: 玩家始终需要验证 直到他们通过验证为止
|
||||
# - DURING_ATTACK: 玩家仅在服务器疑似遭到攻击时验证
|
||||
# - NEVER: 玩家不会被验证
|
||||
# - NEVER: 永远不检查未被验证过的玩家
|
||||
timing: ALWAYS
|
||||
checks:
|
||||
# 检查玩家的下落移动是否遵循原版客户端.
|
||||
gravity:
|
||||
# Sonar 是否应该检查玩家的下落移动? (推荐启用)
|
||||
enabled: true
|
||||
# 当玩家验证失败时 是否向他们发送验证码?
|
||||
# 当玩家验证失败时 是否向他们发送地图验证码?
|
||||
captcha-on-fail: false
|
||||
# 玩家跌落在平台上多少tick后才能被算作站在平台上?
|
||||
max-movement-ticks: 8
|
||||
|
||||
# 检查玩家是否与下方生成的方块发生碰撞
|
||||
# 检查玩家是否可以正确地站在方块上
|
||||
collision:
|
||||
# Sonar 是否应该生成方块平台以检查玩家下落与方块之间的碰撞? (推荐启用)
|
||||
enabled: true
|
||||
|
||||
# 检查客户端坐在实体上时是否发送了正确的数据包
|
||||
vehicle:
|
||||
# 声纳是否应该检查玩家是否正确进入船只?
|
||||
# Sonar 是否应该让玩家坐在实体上, 以便检查他们的数据包是否合法?
|
||||
enabled: true
|
||||
# 客户端发送的最小数据包数量
|
||||
# 客户端需要发送的所需的最小数据包数量
|
||||
minimum-packets: 2
|
||||
|
||||
# 地图验证码
|
||||
# 手持地图验证码
|
||||
map-captcha:
|
||||
# Sonar 应该在什么时候向玩家发送验证码?
|
||||
# 可用类型: ALWAYS, DURING_ATTACK, NEVER
|
||||
@@ -141,8 +142,8 @@ verification:
|
||||
# 为此您必须在服务器软件的配置文件中允许接受来自transfer的连接.
|
||||
# 此外 您可能希望减少 Velocity 或其它服务器软件/插件的登录速率限制
|
||||
# 因为这可能会阻止玩家快速地重新连接到服务器
|
||||
# 如果你的服务器允许 Bedrock 玩家通过间歇泉加入, 请确保为间歇泉设置了
|
||||
# 传输工具 TransferTool, 以便将 Bedrock 玩家重定向到正确的服务器.
|
||||
# 如果你的服务器允许 Bedrock 玩家通过 Geyser 加入, 请确保为 Geyser 设置了
|
||||
# TransferTool 扩展, 以便将 Bedrock 玩家重定向到正确的服务器.
|
||||
# https://github.com/onebeastchris/TransferTool
|
||||
enabled: false
|
||||
# 当玩家通过验证后, Sonar 应该将玩家转移到哪个服务器
|
||||
@@ -153,28 +154,28 @@ verification:
|
||||
# 如果服务器地址不包含端口 请保留25565.
|
||||
destination-port: 25565
|
||||
|
||||
# 玩家在虚拟服务器中的游戏模式
|
||||
# 玩家正在验证时所使用的游戏模式
|
||||
# 可用类型: SURVIVAL, CREATIVE, ADVENTURE
|
||||
# - SURVIVAL: 生存模式, 所有UI可见
|
||||
# - CREATIVE: 创造模式, 隐藏血量和饱食度
|
||||
# - ADVENTURE: 冒险模式, 所有UI可见
|
||||
gamemode: ADVENTURE
|
||||
# 验证世界的夏令时间
|
||||
# 您可以在这里找到所有的夏令时间:
|
||||
# 验证过程中玩家所看到的当前世界中的一天时间
|
||||
# 您可以在这里找到您想要的时间:
|
||||
# https://minecraft.wiki/w/Daylight_cycle
|
||||
# 这只是一个可视化设置, 不会改变验证过程!
|
||||
# 该选项不会改变验证过程.
|
||||
# 如果该值设置为 1000, 则不会发送数据包.
|
||||
time-of-day: 1000
|
||||
# Sonar 缓存它发送到客户端的大部分数据包, 包括 LoginSuccess 数据包.
|
||||
# Sonar 应该使用哪个用户名来接收 LoginSuccess 数据包?
|
||||
# 如果不修改客户端, 用户名将不会对玩家可见
|
||||
cached-username: "Sonar"
|
||||
# 当 Sonar 尝试验证玩家时 是否在控制台中打印它?
|
||||
# 当 Sonar 尝试验证玩家时 是否在控制台中打印有关玩家的信息?
|
||||
log-connections: true
|
||||
# Sonar 是否应该记录在攻击期间内的验证会话?
|
||||
# Sonar 是否应该在攻击期间内打印日志?
|
||||
log-during-attack: false
|
||||
# Sonar 是否应该记录验证过程中玩家的移动位置的变化?
|
||||
# 有助于发现错误 但不建议在非调试环境下的服务器启用该选项.
|
||||
# 有助于发现错误 但不建议在生产环境下的服务器启用该选项.
|
||||
debug-xyz-positions: false
|
||||
# Sonar 是否应该检查来自 Geyser 的(基岩版)玩家?
|
||||
# 此功能是实验性的. 请报告任何因为误判而导致无法通过检查的问题
|
||||
@@ -186,7 +187,7 @@ verification:
|
||||
# 服务器在断开玩家连接前停止发送数据包的时间
|
||||
# (该值为毫秒. 1秒等于1000毫秒.)
|
||||
write-timeout: 10000
|
||||
# 当玩家在需要验证时(即还未通过检查的情况下)需要等待多少毫秒才可以重新连接?
|
||||
# 当玩家在还未通过检查的情况下断开连接后需要等待多少毫秒才可以重新连接?
|
||||
# (该值为毫秒. 1秒等于1000毫秒.)
|
||||
rejoin-delay: 5000
|
||||
# 当玩家验证失败后, Sonar 应该记住他多久?
|
||||
|
||||
@@ -208,6 +208,11 @@ verification:
|
||||
- <yellow>Vaše anti-bot data ještě nejsou připravena.
|
||||
- <gray>Počkejte prosím několik sekund, než se pokusíte znovu ověřit.
|
||||
- <footer>
|
||||
# Zpráva o odpojení, která se zobrazí, když se někdo připojí s nepodporovanou verzí Minecraftu
|
||||
unsupported-version:
|
||||
- <header>
|
||||
- <red>Tento server nepodporuje vaši verzi Minecraftu.
|
||||
- <footer>
|
||||
# Zpráva o odpojení, která se zobrazí, když se někdo znovu připojí příliš rychle během ověření
|
||||
too-fast-reconnect:
|
||||
- <header>
|
||||
|
||||
@@ -203,31 +203,36 @@ verification:
|
||||
# Setzen Sie dies auf '', um die Willkommensnachricht vollständig zu deaktivieren
|
||||
welcome: '<prefix><green>Sie werden gerade überprüft. Bitte bewegen Sie sich nicht, dies ist ein automatischer Vorgang.'
|
||||
|
||||
# Trennungs-Nachricht, die angezeigt wird, wenn jemand beitritt, während der CAPTCHA noch nicht vorbereitet wurde
|
||||
# Nachricht, die angezeigt wird, wenn jemand beitritt, während der CAPTCHA noch nicht vorbereitet wurde
|
||||
currently-preparing:
|
||||
- <header>
|
||||
- <yellow>Deine Anti-Bot-Daten wurden noch nicht vorbereitet.
|
||||
- <gray>Bitte warte einige Sekunden bevor du es erneut versuchst.
|
||||
- <footer>
|
||||
# Trennungs-Nachricht, die angezeigt wird, wenn jemand zu schnell während der Verifizierung erneut beitritt
|
||||
# Nachricht, die angezeigt wird, wenn jemand mit einer nicht unterstützten Minecraft-Version beitritt
|
||||
unsupported-version:
|
||||
- <header>
|
||||
- <red>Dieser Server unterstützt deine Version von Minecraft nicht.
|
||||
- <footer>
|
||||
# Nachricht, die angezeigt wird, wenn jemand zu schnell während der Verifizierung erneut beitritt
|
||||
too-fast-reconnect:
|
||||
- <header>
|
||||
- <gold>Du hast zu schnell erneut eine Verbindung hergestellt, versuche es später noch einmal.
|
||||
- <gray>Bitte warte einige Sekunden bevor du es erneut versuchst.
|
||||
- <footer>
|
||||
# Trennungs-Nachricht, die angezeigt wird, wenn jemand beitritt, aber bereits verifiziert wird
|
||||
# Nachricht, die angezeigt wird, wenn jemand beitritt, aber bereits verifiziert wird
|
||||
already-verifying:
|
||||
- <header>
|
||||
- <red>Deine IP-Adresse wird derzeit verifiziert.
|
||||
- <red>Bitte warte einige Sekunden bevor du es erneut versuchst.
|
||||
- <footer>
|
||||
# Trennungs-Nachricht, die angezeigt wird, wenn jemand beitritt, aber bereits in der Warteschlange für die Verifizierung ist
|
||||
# Nachricht, die angezeigt wird, wenn jemand beitritt, aber bereits in der Warteschlange für die Verifizierung ist
|
||||
already-queued:
|
||||
- <header>
|
||||
- <red>Deine IP-Adresse befindet sich derzeit in der Warteschlange für die Verifizierung.
|
||||
- <red>Bitte warte einige Minuten, bevor du es erneut versuchst.
|
||||
- <footer>
|
||||
# Trennungs-Nachricht, die angezeigt wird, wenn jemand beitritt, aber vorübergehend auf der Blacklist steht
|
||||
# Nachricht, die angezeigt wird, wenn jemand beitritt, aber vorübergehend auf der Blacklist steht
|
||||
blacklisted:
|
||||
- <header>
|
||||
- <red>Du bist derzeit vom Betreten des Servers ausgeschlossen.
|
||||
|
||||
@@ -208,6 +208,11 @@ verification:
|
||||
- <yellow>Your anti-bot data has not been prepared yet.
|
||||
- <gray>Please wait a few seconds before trying to verify again.
|
||||
- <footer>
|
||||
# Disconnect message that is shown when someone joins with an unsupported Minecraft version
|
||||
unsupported-version:
|
||||
- <header>
|
||||
- <red>This server does not support your version of Minecraft.
|
||||
- <footer>
|
||||
# Disconnect message that is shown when someone rejoins too fast during verification
|
||||
too-fast-reconnect:
|
||||
- <header>
|
||||
|
||||
@@ -208,6 +208,11 @@ verification:
|
||||
- <yellow>Tus datos anti-bot aún no se han preparado.
|
||||
- <gray>Espere unos segundos antes de intentar realizar la verificación nuevamente.
|
||||
- <footer>
|
||||
# Mensaje de desconexión que se muestra cuando alguien se une con una versión de Minecraft no soportada
|
||||
unsupported-version:
|
||||
- <header>
|
||||
- <red>Este servidor no es compatible con tu versión de Minecraft.
|
||||
- <footer>
|
||||
# Disconnect message that is shown when someone rejoins too fast during verification
|
||||
too-fast-reconnect:
|
||||
- <header>
|
||||
|
||||
@@ -208,6 +208,11 @@ verification:
|
||||
- <yellow>Vos données anti-bot n'ont pas encore été préparées.
|
||||
- <gray>Veuillez patienter quelques secondes avant d'essayer de vous vérifier à nouveau.
|
||||
- <footer>
|
||||
# Message de déconnexion affiché lorsque quelqu'un se connecte avec une version de Minecraft non prise en charge
|
||||
unsupported-version:
|
||||
- <header>
|
||||
- <red>Ce serveur ne prend pas en charge votre version de Minecraft.
|
||||
- <footer>
|
||||
# Message de déconnexion affiché lorsque quelqu'un se reconnecte trop rapidement pendant la vérification
|
||||
too-fast-reconnect:
|
||||
- <header>
|
||||
|
||||
@@ -208,6 +208,11 @@ verification:
|
||||
- <yellow>Data anti-bot Anda belum disiapkan.
|
||||
- <gray>Silakan tunggu beberapa detik sebelum mencoba verifikasi lagi.
|
||||
- <footer>
|
||||
# Pesan putus yang ditampilkan ketika seseorang bergabung dengan versi Minecraft yang tidak didukung
|
||||
unsupported-version:
|
||||
- <header>
|
||||
- <red>Server ini tidak mendukung versi Minecraft Anda.
|
||||
- <footer>
|
||||
# Pesan putus yang ditampilkan saat seseorang bergabung kembali terlalu cepat selama verifikasi
|
||||
too-fast-reconnect:
|
||||
- <header>
|
||||
|
||||
@@ -208,6 +208,11 @@ verification:
|
||||
- <yellow>ანტიბოტი ჯერ არ მომზადებულა.
|
||||
- <gray>გთხოვთ დაიცადოთ რამოდენიმე წამი სანამ ხელახლა შემოხვალთ.
|
||||
- <footer>
|
||||
# Disconnect message that is shown when someone joins with an unsupported Minecraft version
|
||||
unsupported-version:
|
||||
- <header>
|
||||
- <red>This server does not support your version of Minecraft.
|
||||
- <footer>
|
||||
# გავარდნის მესიჯი რომელიც არის ნაჩვენები როცა ვინმე ხელახლა შემოდის ძალიან სწრაფად შემოწმების დროს.
|
||||
too-fast-reconnect:
|
||||
- <header>
|
||||
|
||||
@@ -208,6 +208,11 @@ verification:
|
||||
- <yellow>Uw anti-bot gegevens zijn nog niet voorbereid.
|
||||
- <gray>Wacht een paar seconden voordat u opnieuw probeert te verifiëren.
|
||||
- <footer>
|
||||
# Verbindingsbericht dat wordt weergegeven wanneer iemand lid wordt met een niet-ondersteunde Minecraft-versie
|
||||
unsupported-version:
|
||||
- <header>
|
||||
- <red>Deze server ondersteunt jouw versie van Minecraft niet.
|
||||
- <footer>
|
||||
# Verbindingsbericht dat wordt weergegeven wanneer iemand tijdens de verificatie te snel opnieuw deelneemt
|
||||
too-fast-reconnect:
|
||||
- <header>
|
||||
|
||||
@@ -211,6 +211,11 @@ verification:
|
||||
- <yellow>Twoje dane antybotowe nie zostały jeszcze przygotowane.
|
||||
- <gray>Odczekaj kilka sekund przed ponowną próbą weryfikacji.
|
||||
- <footer>
|
||||
# Komunikat o rozłączeniu wyświetlany, gdy ktoś dołączy z nieobsługiwaną wersją Minecrafta
|
||||
unsupported-version:
|
||||
- <header>
|
||||
- <red>Ten serwer nie obsługuje twojej wersji gry Minecraft.
|
||||
- <footer>
|
||||
# Disconnect message that is shown when someone rejoins too fast during verification
|
||||
too-fast-reconnect:
|
||||
- <header>
|
||||
|
||||
@@ -208,6 +208,11 @@ verification:
|
||||
- <yellow>Капча еще не подготовлена.
|
||||
- <gray>Пожалуйста, подождите несколько секунд, прежде чем повторить попытку.
|
||||
- <footer>
|
||||
# Сообщение об отключении, которое появляется, когда кто-то присоединяется к серверу с неподдерживаемой версией Minecraft
|
||||
unsupported-version:
|
||||
- <header>
|
||||
- <red>Этот сервер не поддерживает вашу версию Minecraft.
|
||||
- <footer>
|
||||
# Сообщение, которое показывается когда слишком много людей проходят проверку
|
||||
too-many-players:
|
||||
- <header>
|
||||
|
||||
@@ -208,6 +208,11 @@ verification:
|
||||
- <yellow>Anti-bot verileriniz henüz hazır değil.
|
||||
- <gray>Tekrar doğrulamayı denemeden önce lütfen birkaç saniye bekleyin.
|
||||
- <footer>
|
||||
# Birisi desteklenmeyen bir Minecraft sürümüyle katıldığında gösterilen bağlantıyı kes mesajı
|
||||
unsupported-version:
|
||||
- <header>
|
||||
- <red>Bu sunucu senin Minecraft sürümünü desteklemiyor.
|
||||
- <footer>
|
||||
# Doğrulama sırasında birisi çok hızlı bir şekilde yeniden katıldığında gösterilen bağlantıyı kesme mesajı
|
||||
too-fast-reconnect:
|
||||
- <header>
|
||||
|
||||
@@ -27,7 +27,7 @@ footer:
|
||||
# 当玩家尝试加入但有太多在线玩家同时使用者玩家的 IP 地址时显示的踢出消息.
|
||||
too-many-online-per-ip:
|
||||
- '<header>'
|
||||
- <red>您所使用的 IP 地址已经无法再登录更多账户了.
|
||||
- <red>您所使用的 IP 地址已经无法再在该服务器上登录更多账户了.
|
||||
- '<footer>'
|
||||
|
||||
# 有关命令的语言配置.
|
||||
@@ -77,11 +77,11 @@ commands:
|
||||
# '/sonar verbose' 命令的消息
|
||||
verbose:
|
||||
# 该子命令的描述
|
||||
description: "启用或禁用 Sonar 冗余"
|
||||
description: "启用或禁用 Sonar 的实时状态信息"
|
||||
# 玩家订阅详细信息时显示的消息
|
||||
subscribe: '<prefix>已为您显示 Sonar 的详细信息.'
|
||||
subscribe: '<prefix>已为您显示 Sonar 的实时状态信息.'
|
||||
# 玩家取消订阅详细信息时显示的消息
|
||||
unsubscribe: '<prefix>不再为您显示 Sonar 的详细信息.'
|
||||
unsubscribe: '<prefix>不再为您显示 Sonar 的实时状态信息.'
|
||||
|
||||
# '/sonar notify' 命令的消息
|
||||
notify:
|
||||
@@ -95,7 +95,7 @@ commands:
|
||||
# '/sonar blacklist' 命令的消息
|
||||
blacklist:
|
||||
# 该子命令的描述
|
||||
description: "管理黑名单 IP 地址"
|
||||
description: "管理黑名单中的 IP 地址"
|
||||
# 当尝试清理黑名单但黑名单中没有任何 IP 地址显示的消息
|
||||
empty: '<prefix>黑名单中没有任何 IP 地址.'
|
||||
# 当成功清理黑名单时显示的消息
|
||||
@@ -114,7 +114,7 @@ commands:
|
||||
# '/sonar verified' 命令的消息
|
||||
verified:
|
||||
# 该子命令的描述
|
||||
description: "管理已验证的 IP 地址"
|
||||
description: "管理已验证(白名单中)的 IP 地址"
|
||||
# 当尝试清除白名单但为空时显示的消息
|
||||
empty: '<prefix>白名单中没有任何玩家.'
|
||||
# 当成功清理白名单时显示的消息
|
||||
@@ -130,7 +130,7 @@ commands:
|
||||
# 当尝试移除一个不在白名单中的 IP 地址时显示的消息
|
||||
ip-not-found: '<prefix>您提供的 IP 地址不在白名单中.'
|
||||
# 当尝试移除一个查询 IP 地址的验证历史时显示的信息
|
||||
history: '<prefix><yellow>以前的 UUID 用于 <ip>:'
|
||||
history: '<prefix><yellow><ip> 所拥有的历史 UUID:'
|
||||
history-entry: ' <gray>▪ <white><uuid>'
|
||||
|
||||
# '/sonar statistics' 命令的消息
|
||||
@@ -199,8 +199,8 @@ verification:
|
||||
incorrect: '<prefix><red>您输入了错误的答案! 请重试.'
|
||||
|
||||
# 当玩家正在接受验证时显示的信息
|
||||
# 将此项设置为''可完全禁用欢迎信息
|
||||
welcome: '<prefix><green>您正在接受验证. 请不要移动; 这是一个自动过程.'
|
||||
# 将此项设置为''可完全禁用加入时发送的消息
|
||||
welcome: '<prefix><green>正在验证您的客户端. 请不要移动...'
|
||||
|
||||
# 当验证码还在准备的时候显示的踢出消息
|
||||
currently-preparing:
|
||||
@@ -208,6 +208,11 @@ verification:
|
||||
- <yellow>反机器人还在准备所需的数据
|
||||
- <gray>请稍后重新加入服务器
|
||||
- <footer>
|
||||
# 当有人使用不支持的版本加入时显示的断开信息
|
||||
unsupported-version:
|
||||
- <header>
|
||||
- <red>此服务器不支持您的威廉与版本.
|
||||
- <footer>
|
||||
# 当玩家需要验证时重新连接速度太快时显示的踢出消息
|
||||
too-fast-reconnect:
|
||||
- <header>
|
||||
@@ -263,7 +268,7 @@ verbose:
|
||||
# 默认的状态栏
|
||||
normal: '<prefix><gray>每秒连接数 <white><connections-per-second> <dark_aqua>╺ <gray>每秒登录次数 <white><logins-per-second> <dark_aqua>╺ <gray>正在验证的连接数 <white><verifying> <dark_aqua>| <green>⬆ <white><outgoing-traffic>/s <red>⬇ <white><incoming-traffic>/s <green><bold><animation>'
|
||||
# 遭受攻击时的状态栏
|
||||
attack: '<prefix><gray>每秒连接数 <white><connections-per-second> <dark_aqua>╺ <gray>每秒登录次数 <white><logins-per-second> <dark_aqua>╺ <gray>排队连接数 <white><queued> <dark_aqua>╺ <gray>正在验证的连接数 <white><verifying> <dark_aqua>╺ <gray>攻击持续时间 <white><attack-duration> <dark_aqua>| <green>⬆ <white><outgoing-traffic>/s <red>⬇ <white><incoming-traffic>/s <green><bold><animation>'
|
||||
attack: '<prefix><gray>每秒连接数 <white><connections-per-second> <dark_aqua>╺ <gray>每秒登录次数 <white><logins-per-second> <dark_aqua>╺ <gray>正在排队的连接数 <white><queued> <dark_aqua>╺ <gray>正在验证的连接数 <white><verifying> <dark_aqua>╺ <gray>攻击持续时间 <white><attack-duration> <dark_aqua>| <green>⬆ <white><outgoing-traffic>/s <red>⬇ <white><incoming-traffic>/s <green><bold><animation>'
|
||||
# 动画占位符
|
||||
# 其它预设:
|
||||
# - ▙, ▛, ▜, ▟
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
group=xyz.jonesdev
|
||||
version=2.1.12
|
||||
version=2.1.18
|
||||
description=A lightweight, effective, and easy-to-use anti-bot plugin for Velocity, BungeeCord, and Bukkit.
|
||||
@@ -1,5 +1,5 @@
|
||||
[versions]
|
||||
netty = "4.1.114.Final"
|
||||
netty = "4.1.115.Final"
|
||||
adventure = "4.17.0"
|
||||
adventure-platform = "4.3.4"
|
||||
bstats = "3.1.0"
|
||||
@@ -8,7 +8,8 @@ pluginyml = "0.6.0"
|
||||
|
||||
[plugins]
|
||||
indra-git = "net.kyori.indra.git:3.1.3"
|
||||
shadow = "com.gradleup.shadow:8.3.3"
|
||||
shadow = "com.gradleup.shadow:8.3.5"
|
||||
spotless = "com.diffplug.spotless:7.0.0.BETA4"
|
||||
pluginyml-bungee = { id = "net.minecrell.plugin-yml.bungee", version.ref = "pluginyml" }
|
||||
pluginyml-bukkit = { id = "net.minecrell.plugin-yml.bukkit", version.ref = "pluginyml" }
|
||||
|
||||
@@ -31,7 +32,7 @@ caffeine = "com.github.ben-manes.caffeine:caffeine:3.1.8"
|
||||
annotations = "org.jetbrains:annotations:26.0.1"
|
||||
simpleyaml = "com.github.Carleslc.Simple-YAML:Simple-Yaml:1.8.4"
|
||||
ormlite = "com.j256.ormlite:ormlite-jdbc:6.1"
|
||||
lombok = "org.projectlombok:lombok:1.18.34"
|
||||
lombok = "org.projectlombok:lombok:1.18.36"
|
||||
bungeecord = "net.md-5:bungeecord-proxy:1.21-SNAPSHOT"
|
||||
velocity = "com.velocitypowered:velocity-proxy:3.4.0-SNAPSHOT"
|
||||
# We have to use 1.8.8 for backwards compatibility
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
File mode changed.
Reference in new issue
Block a user