diff --git a/build.gradle b/build.gradle index cfedc29a..ffa212a2 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ defaultTasks 'clean', 'shadowJar', 'build' allprojects { group = 'me.xneox' - version = '6.0-SNAPSHOT' + version = '6.0.0' sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 @@ -41,6 +41,7 @@ subprojects { // Shaded dependencies. implementation 'com.maxmind.geoip2:geoip2:2.15.0' implementation 'org.apache.commons:commons-compress:1.20' + implementation 'org.apache.commons:commons-text:1.9' implementation 'com.google.guava:guava:30.1.1-jre' implementation 'com.github.simplix-softworks:SimplixStorage:3.2.2' implementation 'org.spongepowered:configurate-hocon:4.1.1' diff --git a/bukkit/src/main/java/me/xneox/epicguard/bukkit/ChatUtils.java b/bukkit/src/main/java/me/xneox/epicguard/bukkit/ChatUtils.java index 8c69ff42..0b30799c 100644 --- a/bukkit/src/main/java/me/xneox/epicguard/bukkit/ChatUtils.java +++ b/bukkit/src/main/java/me/xneox/epicguard/bukkit/ChatUtils.java @@ -16,6 +16,7 @@ public static void checkUnsupportedVersion(GuardLogger logger) { logger.error(" AND UNSUPPORTED VERSION OF MINECRAFT (1.8)."); logger.error(" Please update to the latest server software."); logger.error(" No support will be provided for any issues."); + logger.error(" https://neox.gitbook.io/epicguard-wiki/faq#spigot-1-8"); logger.error("*******************************************************"); } } diff --git a/core/src/main/java/me/xneox/epicguard/core/EpicGuard.java b/core/src/main/java/me/xneox/epicguard/core/EpicGuard.java index 27b85993..77aa6124 100644 --- a/core/src/main/java/me/xneox/epicguard/core/EpicGuard.java +++ b/core/src/main/java/me/xneox/epicguard/core/EpicGuard.java @@ -105,9 +105,10 @@ private void checkOutdatedJava() { String javaVer = System.getProperty("java.version"); if (javaVer.startsWith("1.8")) { logger().error("*******************************************************"); - logger().error("YOU ARE RUNNING ON AN OUTDATED VERSION OF JAVA (" + javaVer + ")"); - logger().error("Support for this version will be dropped soon, it is recommended to update to Java 16."); - logger().error("It that's not possible, update to at least Java 11."); + logger().error(" YOU ARE RUNNING ON AN OUTDATED VERSION OF JAVA (" + javaVer + ")"); + logger().error(" Support for this version will be dropped soon, it is recommended to update to Java 16."); + logger().error(" It that's not possible, update to at least Java 11."); + logger().error(" https://neox.gitbook.io/epicguard-wiki/faq#java-8"); logger().error("*******************************************************"); } } diff --git a/core/src/main/java/me/xneox/epicguard/core/check/impl/NameSimilarityCheck.java b/core/src/main/java/me/xneox/epicguard/core/check/impl/NameSimilarityCheck.java new file mode 100644 index 00000000..13245580 --- /dev/null +++ b/core/src/main/java/me/xneox/epicguard/core/check/impl/NameSimilarityCheck.java @@ -0,0 +1,36 @@ +package me.xneox.epicguard.core.check.impl; + +import com.google.common.collect.EvictingQueue; +import me.xneox.epicguard.core.EpicGuard; +import me.xneox.epicguard.core.check.Check; +import me.xneox.epicguard.core.user.PendingUser; +import org.apache.commons.text.similarity.LevenshteinDistance; + +import javax.annotation.Nonnull; +import java.util.List; +import java.util.Queue; + +@SuppressWarnings("UnstableApiUsage") +public class NameSimilarityCheck extends Check { + private final Queue nameHistory = EvictingQueue.create(this.epicGuard.config().nameSimilarityCheck().historySize()); + private final LevenshteinDistance distanceAlgorithm = LevenshteinDistance.getDefaultInstance(); + + public NameSimilarityCheck(EpicGuard epicGuard) { + super(epicGuard); + } + + @Override + public boolean handle(@Nonnull PendingUser user) { + for (String nick : this.nameHistory) { + if (this.distanceAlgorithm.apply(nick, user.nickname()) <= this.epicGuard.config().nameSimilarityCheck().distance()) { + return true; + } + } + return false; + } + + @Override + public @Nonnull List kickMessage() { + return this.epicGuard.messages().disconnect().nameSimilarity(); + } +} diff --git a/core/src/main/java/me/xneox/epicguard/core/config/MessagesConfiguration.java b/core/src/main/java/me/xneox/epicguard/core/config/MessagesConfiguration.java index f5ce95a5..32134d35 100644 --- a/core/src/main/java/me/xneox/epicguard/core/config/MessagesConfiguration.java +++ b/core/src/main/java/me/xneox/epicguard/core/config/MessagesConfiguration.java @@ -179,6 +179,10 @@ public static final class Disconnect { "&8» &7You have been kicked by &bAntiBot Protection&7:", "&8» &cYou must add our server to your servers list to verify yourself."); + private final List nameSimilarity = Arrays.asList( + "&8» &7You have been kicked by &bAntiBot Protection&7:", + "&8» &cYour nickname is too similar to other users connecting to the server."); + private final List settingsPacket = Arrays.asList( "&8» &7You have been kicked by &bAntiBot Protection&7:", "&8» &cBot-like behaviour detected, please join the server again."); @@ -215,6 +219,10 @@ public List serverListPing() { return this.serverListPing; } + public List nameSimilarity() { + return this.nameSimilarity; + } + public List settingsPacket() { return this.settingsPacket; } diff --git a/core/src/main/java/me/xneox/epicguard/core/config/PluginConfiguration.java b/core/src/main/java/me/xneox/epicguard/core/config/PluginConfiguration.java index 8932fcd1..7c478869 100644 --- a/core/src/main/java/me/xneox/epicguard/core/config/PluginConfiguration.java +++ b/core/src/main/java/me/xneox/epicguard/core/config/PluginConfiguration.java @@ -32,6 +32,8 @@ public class PluginConfiguration { private final AccountLimitCheck accountLimitCheck = new AccountLimitCheck(); private final SettingsCheck settingsCheck = new SettingsCheck(); private final NicknameCheck nicknameCheck = new NicknameCheck(); + private final NameSimilarityCheck nameSimilarityCheck = new NameSimilarityCheck(); + private final ConsoleFilter consoleFilter = new ConsoleFilter(); private final AutoWhitelist autoWhitelist = new AutoWhitelist(); private final Misc misc = new Misc(); @@ -165,6 +167,39 @@ public String expression() { } } + @ConfigSerializable + public static final class NameSimilarityCheck { + @Comment("NameSimilarityCheck will detect similar nicknames\n" + + "of the connecting users.\n" + + "NEVER - check is disabled.\n" + + "ATTACK - check will be performed only during bot-attack.\n" + + "ALWAYS - check will be always performed.") + private final String checkMode = "ATTACK"; + + @Comment("How many nicknames should be keep in the history?\n" + + "When an user is connecting to the server, his nickname will be added to the history.\n" + + "Then the nickname will be compared with other nicknames stored in the history.\n" + + "(!) Requires restart to apply.") + private final int historySize = 10; + + @Comment("The lower the distance, the similar the names.\n" + + "If the distance detected is lower or the same as\n" + + "configured below, it will be considered as a positive detection.") + private final int distance = 1; + + public String checkMode() { + return this.checkMode; + } + + public int historySize() { + return this.historySize; + } + + public int distance() { + return this.distance; + } + } + @ConfigSerializable public static final class ConsoleFilter { @Comment("Change when the console-filter should be active.\n" + @@ -308,6 +343,10 @@ public NicknameCheck nicknameCheck() { return this.nicknameCheck; } + public NameSimilarityCheck nameSimilarityCheck() { + return this.nameSimilarityCheck; + } + public ConsoleFilter consoleFilter() { return this.consoleFilter; } diff --git a/core/src/main/java/me/xneox/epicguard/core/handler/DetectionHandler.java b/core/src/main/java/me/xneox/epicguard/core/handler/DetectionHandler.java index 769c56d6..aeeb599f 100644 --- a/core/src/main/java/me/xneox/epicguard/core/handler/DetectionHandler.java +++ b/core/src/main/java/me/xneox/epicguard/core/handler/DetectionHandler.java @@ -45,6 +45,7 @@ public DetectionHandler(EpicGuard epicGuard) { checks.add(new ReconnectCheck(epicGuard)); checks.add(new AccountLimitCheck(epicGuard)); checks.add(new NicknameCheck(epicGuard)); + checks.add(new NameSimilarityCheck(epicGuard)); checks.add(new ProxyCheck(epicGuard)); }