├── .github ├── dependabot.yml └── workflows │ └── gradle.yml ├── .gitignore ├── LICENSE ├── README.md ├── VERSION.txt ├── build.gradle.kts ├── codestyle.xml ├── core ├── build.gradle.kts └── src │ └── main │ └── java │ └── me │ └── xneox │ └── epicguard │ └── core │ ├── EpicGuard.java │ ├── EpicGuardAPI.java │ ├── Platform.java │ ├── check │ ├── AbstractCheck.java │ ├── AccountLimitCheck.java │ ├── BlacklistCheck.java │ ├── GeographicalCheck.java │ ├── LockdownCheck.java │ ├── NameSimilarityCheck.java │ ├── NicknameCheck.java │ ├── ProxyCheck.java │ ├── ReconnectCheck.java │ └── ServerListCheck.java │ ├── command │ ├── CommandHandler.java │ ├── SubCommand.java │ └── sub │ │ ├── AnalyzeCommand.java │ │ ├── BlacklistCommand.java │ │ ├── HelpCommand.java │ │ ├── ReloadCommand.java │ │ ├── SaveCommand.java │ │ ├── StatusCommand.java │ │ └── WhitelistCommand.java │ ├── config │ ├── MessagesConfiguration.java │ └── PluginConfiguration.java │ ├── handler │ ├── DisconnectHandler.java │ ├── PingHandler.java │ ├── PostLoginHandler.java │ ├── PreLoginHandler.java │ └── SettingsHandler.java │ ├── manager │ ├── AttackManager.java │ ├── GeoManager.java │ └── UserManager.java │ ├── proxy │ ├── ProxyManager.java │ ├── ProxyService.java │ └── ProxyServiceSerializer.java │ ├── storage │ ├── AddressMeta.java │ ├── Database.java │ └── StorageManager.java │ ├── task │ ├── AttackResetTask.java │ ├── DataSaveTask.java │ ├── MonitorTask.java │ └── UpdateCheckerTask.java │ ├── user │ ├── ConnectingUser.java │ └── OnlineUser.java │ └── util │ ├── ConfigurationLoader.java │ ├── FileUtils.java │ ├── LogUtils.java │ ├── TextUtils.java │ ├── ToggleState.java │ ├── URLUtils.java │ ├── VersionUtils.java │ └── logging │ └── LogFilter.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jitpack.yml ├── paper ├── build.gradle.kts └── src │ └── main │ ├── java │ └── me │ │ └── xneox │ │ └── epicguard │ │ └── paper │ │ ├── EpicGuardPaper.java │ │ ├── PaperCommandHandler.java │ │ └── listener │ │ ├── PlayerPostLoginListener.java │ │ ├── PlayerPreLoginListener.java │ │ ├── PlayerQuitListener.java │ │ ├── PlayerSettingsListener.java │ │ └── ServerPingListener.java │ └── resources │ └── plugin.yml ├── settings.gradle.kts ├── velocity ├── build.gradle.kts └── src │ └── main │ └── java │ └── me │ └── xneox │ └── epicguard │ └── velocity │ ├── EpicGuardVelocity.java │ ├── VelocityCommandHandler.java │ └── listener │ ├── DisconnectListener.java │ ├── PlayerSettingsListener.java │ ├── PostLoginListener.java │ ├── PreLoginListener.java │ └── ServerPingListener.java └── waterfall ├── build.gradle.kts └── src └── main ├── java └── me │ └── xneox │ └── epicguard │ └── waterfall │ ├── BungeeCommandHandler.java │ ├── BungeeUtils.java │ ├── EpicGuardWaterfall.java │ └── listener │ ├── DisconnectListener.java │ ├── PlayerSettingsListener.java │ ├── PostLoginListener.java │ ├── PreLoginListener.java │ └── ServerPingListener.java └── resources └── plugin.yml /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: gradle 5 | directory: "/" 6 | schedule: 7 | interval: daily -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Gradle 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle 3 | 4 | name: Java CI 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up JDK 17 18 | uses: actions/setup-java@v2 19 | with: 20 | java-version: 17 21 | distribution: 'temurin' 22 | - uses: burrunan/gradle-cache-action@v1 23 | name: Build with Gradle 24 | with: 25 | arguments: build 26 | gradle-version: wrapper 27 | - name: Upload build artifact 28 | uses: actions/upload-artifact@v2 29 | with: 30 | name: artifact 31 | path: build/ 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/java,intellij,gradle 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=java,intellij,gradle 4 | 5 | ### Intellij ### 6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 7 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 8 | 9 | # User-specific stuff 10 | .idea/**/workspace.xml 11 | .idea/**/tasks.xml 12 | .idea/**/usage.statistics.xml 13 | .idea/**/dictionaries 14 | .idea/**/shelf 15 | 16 | # Generated files 17 | .idea/**/contentModel.xml 18 | 19 | # Sensitive or high-churn files 20 | .idea/**/dataSources/ 21 | .idea/**/dataSources.ids 22 | .idea/**/dataSources.local.xml 23 | .idea/**/sqlDataSources.xml 24 | .idea/**/dynamic.xml 25 | .idea/**/uiDesigner.xml 26 | .idea/**/dbnavigator.xml 27 | 28 | # Gradle 29 | .idea/**/gradle.xml 30 | .idea/**/libraries 31 | 32 | # Gradle and Maven with auto-import 33 | # When using Gradle or Maven with auto-import, you should exclude module files, 34 | # since they will be recreated, and may cause churn. Uncomment if using 35 | # auto-import. 36 | # .idea/artifacts 37 | # .idea/compiler.xml 38 | # .idea/jarRepositories.xml 39 | # .idea/modules.xml 40 | # .idea/*.iml 41 | # .idea/modules 42 | # *.iml 43 | # *.ipr 44 | 45 | # CMake 46 | cmake-build-*/ 47 | 48 | # Mongo Explorer plugin 49 | .idea/**/mongoSettings.xml 50 | 51 | # File-based project format 52 | *.iws 53 | 54 | # IntelliJ 55 | out/ 56 | 57 | # mpeltonen/sbt-idea plugin 58 | .idea_modules/ 59 | 60 | # JIRA plugin 61 | atlassian-ide-plugin.xml 62 | 63 | # Cursive Clojure plugin 64 | .idea/replstate.xml 65 | 66 | # Crashlytics plugin (for Android Studio and IntelliJ) 67 | com_crashlytics_export_strings.xml 68 | crashlytics.properties 69 | crashlytics-build.properties 70 | fabric.properties 71 | 72 | # Editor-based Rest Client 73 | .idea/httpRequests 74 | 75 | # Android studio 3.1+ serialized cache file 76 | .idea/caches/build_file_checksums.ser 77 | 78 | ### Intellij Patch ### 79 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 80 | 81 | # *.iml 82 | # modules.xml 83 | # .idea/misc.xml 84 | # *.ipr 85 | 86 | # Sonarlint plugin 87 | # https://plugins.jetbrains.com/plugin/7973-sonarlint 88 | .idea/**/sonarlint/ 89 | 90 | # SonarQube Plugin 91 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin 92 | .idea/**/sonarIssues.xml 93 | 94 | # Markdown Navigator plugin 95 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced 96 | .idea/**/markdown-navigator.xml 97 | .idea/**/markdown-navigator-enh.xml 98 | .idea/**/markdown-navigator/ 99 | 100 | # Cache file creation bug 101 | # See https://youtrack.jetbrains.com/issue/JBR-2257 102 | .idea/$CACHE_FILE$ 103 | 104 | # CodeStream plugin 105 | # https://plugins.jetbrains.com/plugin/12206-codestream 106 | .idea/codestream.xml 107 | 108 | ### Java ### 109 | # Compiled class file 110 | *.class 111 | 112 | # Log file 113 | *.log 114 | 115 | # BlueJ files 116 | *.ctxt 117 | 118 | # Mobile Tools for Java (J2ME) 119 | .mtj.tmp/ 120 | 121 | # Package Files # 122 | *.jar 123 | *.war 124 | *.nar 125 | *.ear 126 | *.zip 127 | *.tar.gz 128 | *.rar 129 | 130 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 131 | hs_err_pid* 132 | 133 | ### Gradle ### 134 | .gradle 135 | build/ 136 | 137 | # Ignore Gradle GUI config 138 | gradle-app.setting 139 | 140 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 141 | !gradle-wrapper.jar 142 | 143 | # Cache of project 144 | .gradletasknamecache 145 | 146 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 147 | # gradle/wrapper/gradle-wrapper.properties 148 | 149 | ### Gradle Patch ### 150 | **/build/ 151 | 152 | # End of https://www.toptal.com/developers/gitignore/api/java,intellij,gradle 153 | /.idea/ 154 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🚧️ Maintained fork can be found at: https://github.com/4drian3d/EpicGuard 2 | # 🛡 EpicGuard [![GitHub stars](https://img.shields.io/github/stars/xxneox/EpicGuard)](https://github.com/xxneox/EpicGuard/stargazers) [![GitHub forks](https://img.shields.io/github/forks/xxneox/EpicGuard)](https://github.com/xxneox/EpicGuard/network) [![GitHub issues](https://img.shields.io/github/issues/xxneox/EpicGuard)](https://github.com/xxneox/EpicGuard/issues) [![GitHub license](https://img.shields.io/github/license/xxneox/EpicGuard)](https://github.com/xxneox/EpicGuard/blob/master/LICENSE) [![Java CI](https://github.com/xxneox/EpicGuard/actions/workflows/gradle.yml/badge.svg)](https://github.com/xxneox/EpicGuard/actions/workflows/gradle.yml) 3 | A simple AntiBot plugin for newest Minecraft versions. 4 | 5 | ## ✅ Supported platforms / Latest release requirements 6 | * [Paper 1.17+](https://papermc.io/) *(all paper forks are supported)* 7 | * [Velocity 3.0+](https://velocitypowered.com/) 8 | * BungeeCord *([Waterfall](https://papermc.io/downloads#Waterfall) required fork)* 9 | * Java **17** 10 | 11 | ## ✨ Features 12 | * A total of **8** configurable antibot checks: 13 | * Geographical check - country/city blacklist or whitelist. 14 | * VPN/Proxy check - configurable services and caching. 15 | * Nickname check - block certain nickname patterns using regex. 16 | * Reconnect check - require re-joining the server with an identical pair of address and nickname. 17 | * Server list check - require pinging the server before connecting (adding it to the server list). 18 | * Settings check - make sure that player sends a settings packet after joining (vanilla client behaviour). 19 | * Lockdown - temporarily block incoming connections if there are too many of them. 20 | * Name similiarity check (BETA) 21 | * Account limit. 22 | * SQLite/MySQL support. 23 | * Live actionbar statistics. 24 | * Automatic whitelisting. 25 | * Console filter. 26 | 27 | ## 📚 Commands & Permissions 28 | To be able to use commands, give yourself the **epicguard.admin** permission. 29 | On different platforms there are additional aliases available, such as **/guardvelocity** or **/epicguardpaper** 30 | 31 | | Command | Description | 32 | |----------------------------------------------|------------------------------------------------------------------------| 33 | | /guard help | Displays all available commands. | 34 | | /guard reload | Reloads config and messages. | 35 | | /guard whitelist | Whitelist/unwhitelist an address or nickname. | 36 | | /guard blacklist | Blacklist/unblacklist an address or nickname. | 37 | | /guard analyze | Displays detailed information about the specified address or nickname. | 38 | | /guard status | Toggles live attack information on actionbar. | 39 | | /guard save | Forces save to the database. | 40 | 41 | ## ⚠️ Current state of the project 42 | I (xxneox) am basically the only maintainer of this project. I don't have time to work on it anymore, so it's only getting bugfixes and important changes. Support is only given for important issues. This repository *might* get archived at any time. 43 | 44 | ## 🔧 Using EpicGuard API in your project: 45 | The api is not very advanced, and there is not much you can do with it for now. 46 |
47 | Gradle (Groovy) 48 | 49 | ```groovy 50 | repositories { 51 | maven { 52 | url = 'https://jitpack.io' 53 | } 54 | } 55 | 56 | dependencies { 57 | compileOnly 'com.github.xxneox:EpicGuard:[VERSION OR COMMIT ID HERE]' 58 | } 59 | ``` 60 |
61 | 62 |
63 | Gradle (Kotlin) 64 | 65 | ```kotlin 66 | repositories { 67 | maven("https://jitpack.io") 68 | } 69 | 70 | dependencies { 71 | compileOnly("com.github.xxneox:EpicGuard:[VERSION OR COMMIT ID HERE]") 72 | } 73 | ``` 74 |
75 | 76 |
77 | Maven 78 | 79 | ```xml 80 | 81 | 82 | jitpack.io 83 | https://jitpack.io 84 | 85 | 86 | 87 | 88 | 89 | com.github.xxneox 90 | EpicGuard 91 | [VERSION OR COMMIT ID HERE] 92 | provided 93 | 94 | 95 | ``` 96 |
97 | 98 |
99 | Using the API 100 | Make sure that EpicGuard is fully loaded before your plugin. 101 | 102 | [Click to see the API class](https://github.com/xxneox/EpicGuard/blob/master/core/src/main/java/me/xneox/epicguard/core/EpicGuardAPI.java) 103 | 104 | ```java 105 | // Importing the API class. 106 | import me.xneox.epicguard.core.EpicGuardAPI; 107 | import me.xneox.epicguard.core.manager.AttackManager; 108 | 109 | public class EpicGuardAPIExample { 110 | // Accessing the EpicGuardAPI instance. 111 | EpicGuardAPI api = EpicGuardAPI.INSTANCE; 112 | 113 | // Obtaining the AttackManager instance: 114 | AttackManager attackManager = api.attackManager(); 115 | 116 | // Checking if server is under attack. 117 | boolean isUnderAttack = attackManager.isUnderAttack(); 118 | 119 | // checking current connections per second. 120 | int cps = attackManager.connectionCounter(); 121 | 122 | // Checking user's country: 123 | String countryId = api.geoManager().countryCode("127.0.0.1"); 124 | } 125 | ``` 126 |
127 | 128 | ## 🕵️ Privacy disclaimers 129 | * This plugin connect to various external services, to fully work as intended. 130 | * [Maxind's Geolite2 databases](https://dev.maxmind.com/geoip/geoip2/geolite2) (country and city) are downloaded at the first startup and updated every week. Geolocation of your users is checked locally on your server. 131 | * *In the default configuration*, IP addresses of connecting users are sent to https://proxycheck.io/ to check if they're not using a proxy or a VPN. 132 | * IPs and nicknames associated with them are stored in the local database *(as plain text(!))*. 133 | * This plugin periodically checks the latest version released in this repository. *This feature can be disabled.* 134 | * *There is no metrics system or any other kind of data collection.* 135 | -------------------------------------------------------------------------------- /VERSION.txt: -------------------------------------------------------------------------------- 1 | 7.1.2 -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar 2 | 3 | plugins { 4 | java 5 | id("com.github.johnrengelman.shadow") version "7.1.0" 6 | } 7 | 8 | allprojects { 9 | apply(plugin = "java") 10 | apply(plugin = "com.github.johnrengelman.shadow") 11 | 12 | java { 13 | toolchain { 14 | languageVersion.set(JavaLanguageVersion.of(17)) 15 | } 16 | } 17 | } 18 | 19 | subprojects { 20 | tasks.withType { 21 | val platformName = project.name.capitalize() 22 | archiveFileName.set("EpicGuard$platformName-${project.version}.jar") 23 | 24 | relocate("org.spongepowered.configurate", "me.xneox.epicguard.libs.configurate") 25 | relocate("org.apache.commons", "me.xneox.epicguard.libs.apachecommons") 26 | relocate("com.fasterxml", "me.xneox.epicguard.libs.fasterxml") 27 | relocate("com.maxmind", "me.xneox.epicguard.libs.maxmind") 28 | relocate("com.google.common", "me.xneox.epicguard.libs.googlecommons") 29 | relocate("com.typesafe.config", "me.xneox.epicguard.libs.config") 30 | relocate("com.zaxxer.hikari", "me.xneox.epicguard.libs.hikari") 31 | relocate("io.leangen.geantyref", "me.xneox.epicguard.libs.geantyref") 32 | 33 | // Minimize, but exclude drivers shaded in the velocity platform. 34 | minimize { 35 | exclude(dependency("mysql:.*:.*")) 36 | exclude(dependency("org.xerial:sqlite-jdbc:.*")) 37 | } 38 | 39 | // Copy compiled platform jars to '/build' directory for convenience. 40 | doLast { 41 | copy { 42 | from(archiveFile) 43 | into("${rootProject.projectDir}/build") 44 | } 45 | } 46 | } 47 | 48 | tasks.withType { 49 | options.encoding = Charsets.UTF_8.name() 50 | options.release.set(16) 51 | } 52 | 53 | // For Waterfall and Paper platforms: set version 54 | tasks.withType { 55 | filesMatching("plugin.yml") { 56 | expand("version" to project.version) 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `maven-publish` 3 | id("net.kyori.blossom") version "1.3.0" 4 | } 5 | 6 | dependencies { 7 | implementation("com.maxmind.geoip2:geoip2:2.16.1") 8 | implementation("org.apache.commons:commons-compress:1.21") 9 | implementation("org.apache.commons:commons-text:1.9") 10 | implementation("com.google.guava:guava:31.0.1-jre") 11 | implementation("org.spongepowered:configurate-hocon:4.1.2") 12 | implementation("org.jetbrains:annotations:23.0.0") 13 | implementation("com.zaxxer:HikariCP:5.0.0") 14 | 15 | compileOnly("net.kyori:adventure-api:4.9.3") 16 | compileOnly("net.kyori:adventure-text-serializer-legacy:4.9.3") 17 | compileOnly("org.apache.logging.log4j:log4j-core:2.15.0") 18 | compileOnly("org.slf4j:slf4j-api:1.7.32") 19 | } 20 | 21 | blossom { 22 | replaceToken("{version}", project.version, "src/main/java/me/xneox/epicguard/core/util/VersionUtils.java") 23 | } 24 | 25 | // Publish to jitpack.org 26 | publishing { 27 | publications { 28 | create("maven") { 29 | artifactId = "EpicGuard" 30 | 31 | from(components["java"]) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/EpicGuard.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core; 17 | 18 | import java.io.File; 19 | import java.sql.SQLException; 20 | import java.util.concurrent.TimeUnit; 21 | import me.xneox.epicguard.core.config.MessagesConfiguration; 22 | import me.xneox.epicguard.core.config.PluginConfiguration; 23 | import me.xneox.epicguard.core.proxy.ProxyService; 24 | import me.xneox.epicguard.core.proxy.ProxyServiceSerializer; 25 | import me.xneox.epicguard.core.util.LogUtils; 26 | import me.xneox.epicguard.core.util.VersionUtils; 27 | import me.xneox.epicguard.core.util.logging.LogFilter; 28 | import me.xneox.epicguard.core.manager.AttackManager; 29 | import me.xneox.epicguard.core.manager.GeoManager; 30 | import me.xneox.epicguard.core.manager.UserManager; 31 | import me.xneox.epicguard.core.proxy.ProxyManager; 32 | import me.xneox.epicguard.core.storage.StorageManager; 33 | import me.xneox.epicguard.core.task.AttackResetTask; 34 | import me.xneox.epicguard.core.task.DataSaveTask; 35 | import me.xneox.epicguard.core.task.MonitorTask; 36 | import me.xneox.epicguard.core.task.UpdateCheckerTask; 37 | import me.xneox.epicguard.core.util.ConfigurationLoader; 38 | import me.xneox.epicguard.core.util.FileUtils; 39 | import org.jetbrains.annotations.NotNull; 40 | import org.slf4j.Logger; 41 | import org.spongepowered.configurate.ConfigurateException; 42 | import org.spongepowered.configurate.hocon.HoconConfigurationLoader; 43 | 44 | /** 45 | * The main class of the EpicGuard's core. 46 | * Initializes everything and holds all managers. 47 | */ 48 | public class EpicGuard { 49 | private final Platform platform; 50 | 51 | private StorageManager storageManager; 52 | private GeoManager geoManager; 53 | private UserManager userManager; 54 | private AttackManager attackManager; 55 | private ProxyManager proxyManager; 56 | 57 | private PluginConfiguration config; 58 | private MessagesConfiguration messages; 59 | 60 | public EpicGuard(Platform platform) { 61 | this.platform = platform; 62 | this.startup(); 63 | } 64 | 65 | private void startup() { 66 | logger().info("Running on: " + this.platform.platformVersion()); 67 | EpicGuardAPI.INSTANCE.instance(this); 68 | 69 | logger().info("Loading configuration..."); 70 | this.loadConfigurations(); 71 | 72 | logger().info("Initializing managers..."); 73 | this.geoManager = new GeoManager(this); 74 | this.proxyManager = new ProxyManager(this); 75 | this.attackManager = new AttackManager(); 76 | this.userManager = new UserManager(); 77 | 78 | this.storageManager = new StorageManager(this); 79 | this.storageManager.setupDatabase(); 80 | 81 | logger().info("Initializing LogFilter..."); 82 | new LogFilter(this).register(); 83 | 84 | logger().info("Scheduling tasks..."); 85 | this.platform.scheduleRepeatingTask(new MonitorTask(this), 1L); 86 | this.platform.scheduleRepeatingTask(new UpdateCheckerTask(this), 1800L); 87 | this.platform.scheduleRepeatingTask(new AttackResetTask(this), this.config.misc().attackResetInterval()); 88 | this.platform.scheduleRepeatingTask(new DataSaveTask(this), TimeUnit.MINUTES.toSeconds(this.config.misc().autoSaveInterval())); 89 | 90 | logger().info("Startup completed successfully. Welcome to EpicGuard v" + VersionUtils.CURRENT_VERSION); 91 | } 92 | 93 | public void loadConfigurations() { 94 | var configLoader = HoconConfigurationLoader.builder() 95 | .defaultOptions(opt -> opt.serializers(builder -> builder.register(ProxyService.class, ProxyServiceSerializer.INSTANCE))) 96 | .file(new File(FileUtils.EPICGUARD_DIR, "settings.conf")) 97 | .build(); 98 | 99 | var messagesLoader = HoconConfigurationLoader.builder() 100 | .file(new File(FileUtils.EPICGUARD_DIR, "messages.conf")) 101 | .build(); 102 | 103 | try { 104 | this.config = new ConfigurationLoader<>(PluginConfiguration.class, configLoader).load(); 105 | this.messages = new ConfigurationLoader<>(MessagesConfiguration.class, messagesLoader).load(); 106 | } catch (ConfigurateException exception) { 107 | LogUtils.catchException("Couldn't load the configuration file", exception); 108 | } 109 | } 110 | 111 | public void shutdown() { 112 | try { 113 | this.storageManager.database().save(); 114 | this.storageManager.database().shutdown(); 115 | } catch (SQLException exception) { 116 | LogUtils.catchException("Could not save data to the SQL database (during shutdown)", exception); 117 | } 118 | } 119 | 120 | @NotNull 121 | public Logger logger() { 122 | return this.platform.logger(); 123 | } 124 | 125 | @NotNull 126 | public Platform platform() { 127 | return this.platform; 128 | } 129 | 130 | @NotNull 131 | public PluginConfiguration config() { 132 | return this.config; 133 | } 134 | 135 | @NotNull 136 | public MessagesConfiguration messages() { 137 | return this.messages; 138 | } 139 | 140 | @NotNull 141 | public UserManager userManager() { 142 | return this.userManager; 143 | } 144 | 145 | @NotNull 146 | public GeoManager geoManager() { 147 | return this.geoManager; 148 | } 149 | 150 | @NotNull 151 | public StorageManager storageManager() { 152 | return this.storageManager; 153 | } 154 | 155 | @NotNull 156 | public AttackManager attackManager() { 157 | return this.attackManager; 158 | } 159 | 160 | @NotNull 161 | public ProxyManager proxyManager() { 162 | return this.proxyManager; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/EpicGuardAPI.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core; 17 | 18 | import java.util.Collection; 19 | import me.xneox.epicguard.core.manager.AttackManager; 20 | import me.xneox.epicguard.core.manager.GeoManager; 21 | import me.xneox.epicguard.core.storage.AddressMeta; 22 | import me.xneox.epicguard.core.storage.StorageManager; 23 | import org.apache.commons.lang3.Validate; 24 | import org.jetbrains.annotations.NotNull; 25 | 26 | /** 27 | * A singleton API class which can be safely used by other projects. 28 | */ 29 | public class EpicGuardAPI { 30 | 31 | public static final EpicGuardAPI INSTANCE = new EpicGuardAPI(); 32 | private EpicGuard epicGuard; 33 | 34 | /** 35 | * The {@link GeoManager} class contains methods that you may find useful if you want to check 36 | * country/city of an address. 37 | * 38 | * @return An instance of {@link GeoManager}. 39 | */ 40 | @NotNull 41 | public GeoManager geoManager() { 42 | checkAvailability(); 43 | return this.epicGuard.geoManager(); 44 | } 45 | 46 | /** 47 | * @return The storage manager, which is used for various things regarding address data. 48 | */ 49 | @NotNull 50 | public StorageManager storageManager() { 51 | checkAvailability(); 52 | return this.epicGuard.storageManager(); 53 | } 54 | 55 | /** 56 | * @return The attack manager which contains methods for managing the attack status. 57 | */ 58 | public AttackManager attackManager() { 59 | checkAvailability(); 60 | return this.epicGuard.attackManager(); 61 | } 62 | 63 | /** 64 | * @return An immutable Collection which contains whitelisted addresses. 65 | */ 66 | @NotNull 67 | public Collection whitelistedAddresses() { 68 | checkAvailability(); 69 | return this.epicGuard.storageManager().viewAddresses(AddressMeta::whitelisted); 70 | } 71 | 72 | /** 73 | * @return An immutable Collection which contains blacklisted addresses. 74 | */ 75 | @NotNull 76 | public Collection blacklistedAddresses() { 77 | checkAvailability(); 78 | return this.epicGuard.storageManager().viewAddresses(AddressMeta::blacklisted); 79 | } 80 | 81 | /** 82 | * @return The platform name and version EpicGuard is currently running on. 83 | */ 84 | @NotNull 85 | public String platformVersion() { 86 | return this.epicGuard.platform().platformVersion(); 87 | } 88 | 89 | /** 90 | * @return The instance of EpicGuard's core. Use at your own risk. 91 | */ 92 | public EpicGuard instance() { 93 | return this.epicGuard; 94 | } 95 | 96 | /** 97 | * This method is used during initialization to set an instance. Can't be used twice. 98 | * 99 | * @param instance Instance of {@link EpicGuard} class. 100 | */ 101 | protected void instance(@NotNull EpicGuard instance) { 102 | if (this.epicGuard == null) { 103 | this.epicGuard = instance; 104 | } else { 105 | throw new UnsupportedOperationException("Instance already set."); 106 | } 107 | } 108 | 109 | /** 110 | * Checks if the EpicGuard has been initialized already. 111 | */ 112 | public void checkAvailability() { 113 | Validate.notNull(this.epicGuard, "Can't acces EpicGuardAPI because the plugin is not initialized. Have you set is as dependency?."); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/Platform.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core; 17 | 18 | import java.util.UUID; 19 | import net.kyori.adventure.audience.Audience; 20 | import net.kyori.adventure.text.Component; 21 | import org.jetbrains.annotations.NotNull; 22 | import org.jetbrains.annotations.Nullable; 23 | import org.slf4j.Logger; 24 | 25 | public interface Platform { 26 | /** 27 | * @return Name and version of this platform. 28 | */ 29 | @NotNull 30 | String platformVersion(); 31 | 32 | /** 33 | * @return A wrapper of the platform plugin's logger. 34 | */ 35 | @NotNull 36 | Logger logger(); 37 | 38 | /** 39 | * @param uuid UUID of the online user. 40 | * @return an audience for the provided user's uuid. 41 | */ 42 | @Nullable 43 | Audience audience(@NotNull UUID uuid); 44 | 45 | /** 46 | * Kicks the user from the server with a specified message (find the player using User#getUUID). 47 | * 48 | * @param uuid The UUID of user to be kicked. 49 | * @param message The kick message. 50 | */ 51 | void disconnectUser(@NotNull UUID uuid, @NotNull Component message); 52 | 53 | /** 54 | * Schedules a task to be run asynchronously after the specified time (in seconds). 55 | * 56 | * @param task The task to be scheduled. 57 | * @param seconds Delay in seconds after the task should be ran. 58 | */ 59 | void runTaskLater(@NotNull Runnable task, long seconds); 60 | 61 | /** 62 | * Schedules a task to be run asynchronously repeatedly with fixed delay (in seconds). 63 | * 64 | * @param task The task to be scheduled. 65 | * @param seconds Delay in seconds between each runs of the task. 66 | */ 67 | void scheduleRepeatingTask(@NotNull Runnable task, long seconds); 68 | } 69 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/check/AbstractCheck.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.check; 17 | 18 | import java.util.List; 19 | import me.xneox.epicguard.core.EpicGuard; 20 | import me.xneox.epicguard.core.user.ConnectingUser; 21 | import me.xneox.epicguard.core.util.TextUtils; 22 | import me.xneox.epicguard.core.util.ToggleState; 23 | import net.kyori.adventure.text.TextComponent; 24 | import org.jetbrains.annotations.NotNull; 25 | 26 | public abstract class AbstractCheck implements Comparable { 27 | protected final EpicGuard epicGuard; 28 | 29 | private final int priority; 30 | private final TextComponent detectionMessage; 31 | 32 | public AbstractCheck(@NotNull EpicGuard epicGuard, @NotNull List detectionMessage, int priority) { 33 | this.epicGuard = epicGuard; 34 | this.detectionMessage = TextUtils.multilineComponent(detectionMessage); 35 | this.priority = priority; 36 | } 37 | 38 | /** 39 | * Method containing the check's logic, it's return value determines if 40 | * the user will be disconnected or if the pipeline will continue checking the user. 41 | * 42 | * @param user the connecting user. 43 | * @return true if detected, false if not 44 | */ 45 | public abstract boolean isDetected(@NotNull ConnectingUser user); 46 | 47 | /** 48 | * This method asserts the following behavoiur based on the provided {@link ToggleState}: 49 | * - If the state is ALWAYS, it will return the value of the specified expression. 50 | * - If the state is ATTACK, it will return the value of the expression ONLY if there's an attack. 51 | * - If the state is NEVER, it will return false. 52 | * 53 | * @param state the configured {@link ToggleState} for this check 54 | * @param expression the base check's result 55 | * @return The return value is based on the check's behaviour. True means positive detection, 56 | * false means negative. 57 | */ 58 | public boolean evaluate(ToggleState state, boolean expression) { 59 | if (state == ToggleState.ALWAYS || state == ToggleState.ATTACK && this.epicGuard.attackManager().isUnderAttack()) { 60 | return expression; 61 | } 62 | return false; 63 | } 64 | 65 | /** 66 | * A formatted {@link TextComponent} which is a disconnect message for this check. 67 | * 68 | * @return disconnect message of this check 69 | */ 70 | @NotNull 71 | public TextComponent detectionMessage() { 72 | return this.detectionMessage; 73 | } 74 | 75 | /** 76 | * Compares the priority of this check to another check. 77 | * Used to automatically sort the checks in the pipeline. 78 | * 79 | * @param other the other check 80 | * @return result of the method {@link Integer#compare(int, int)} 81 | */ 82 | @Override 83 | public int compareTo(@NotNull AbstractCheck other) { 84 | return Integer.compare(other.priority, this.priority); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/check/AccountLimitCheck.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.check; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.user.ConnectingUser; 20 | import org.jetbrains.annotations.NotNull; 21 | 22 | /** 23 | * This check limits how many accounts can be created on one address. 24 | */ 25 | public class AccountLimitCheck extends AbstractCheck { 26 | public AccountLimitCheck(EpicGuard epicGuard) { 27 | super(epicGuard, epicGuard.messages().disconnect().accountLimit(), epicGuard.config().accountLimitCheck().priority()); 28 | } 29 | 30 | @Override 31 | public boolean isDetected(@NotNull ConnectingUser user) { 32 | var accounts = this.epicGuard.storageManager().addressMeta(user.address()).nicknames(); 33 | return this.evaluate(this.epicGuard.config().accountLimitCheck().checkMode(), 34 | !accounts.contains(user.nickname()) && accounts.size() >= this.epicGuard.config().accountLimitCheck().accountLimit()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/check/BlacklistCheck.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.check; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.check.AbstractCheck; 20 | import me.xneox.epicguard.core.user.ConnectingUser; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | /** 24 | * This just checks if the user is blacklisted. 25 | */ 26 | public class BlacklistCheck extends AbstractCheck { 27 | public BlacklistCheck(EpicGuard epicGuard) { 28 | super(epicGuard, epicGuard.messages().disconnect().blacklisted(), 98); // will always be executed secondly. 29 | } 30 | 31 | @Override 32 | public boolean isDetected(@NotNull ConnectingUser user) { 33 | return this.epicGuard.storageManager().addressMeta(user.address()).blacklisted(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/check/GeographicalCheck.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.check; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.check.AbstractCheck; 20 | import me.xneox.epicguard.core.user.ConnectingUser; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | /** 24 | * This checks if the user's geographical location is allowed based on the current configuration. 25 | */ 26 | public class GeographicalCheck extends AbstractCheck { 27 | public GeographicalCheck(EpicGuard epicGuard) { 28 | super(epicGuard, epicGuard.messages().disconnect().geographical(), epicGuard.config().geographical().priority()); 29 | } 30 | 31 | @Override 32 | public boolean isDetected(@NotNull ConnectingUser user) { 33 | return this.evaluate(this.epicGuard.config().geographical().checkMode(), this.isRestricted(user.address())); 34 | } 35 | 36 | private boolean isRestricted(String address) { 37 | String country = this.epicGuard.geoManager().countryCode(address); 38 | String city = this.epicGuard.geoManager().city(address); 39 | 40 | if (this.epicGuard.config().geographical().cityBlacklist().contains(city)) { 41 | return true; 42 | } 43 | 44 | if (this.epicGuard.config().geographical().isBlacklist()) { 45 | return this.epicGuard.config().geographical().countries().contains(country); 46 | } else { 47 | return !this.epicGuard.config().geographical().countries().contains(country); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/check/LockdownCheck.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.check; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.user.ConnectingUser; 20 | import org.jetbrains.annotations.NotNull; 21 | 22 | /** 23 | * This check denies any connection if the attack mode is active. 24 | */ 25 | public class LockdownCheck extends AbstractCheck { 26 | public LockdownCheck(EpicGuard epicGuard) { 27 | super(epicGuard, epicGuard.messages().disconnect().attackLockdown(), 99); // will always be executed first 28 | } 29 | 30 | @Override 31 | public boolean isDetected(@NotNull ConnectingUser user) { 32 | return this.epicGuard.attackManager().isUnderAttack() && this.epicGuard.config().misc().lockdownOnAttack(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/check/NameSimilarityCheck.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.check; 17 | 18 | import com.google.common.collect.EvictingQueue; 19 | import me.xneox.epicguard.core.EpicGuard; 20 | import me.xneox.epicguard.core.user.ConnectingUser; 21 | import org.apache.commons.text.similarity.LevenshteinDistance; 22 | import org.jetbrains.annotations.NotNull; 23 | 24 | import java.util.Queue; 25 | 26 | /** 27 | * This check caches nicknames of the recently connecting users, 28 | * and uses {@link LevenshteinDistance} to check similarity between them. 29 | * Not tested, may be unstable. 30 | */ 31 | @SuppressWarnings("UnstableApiUsage") 32 | public class NameSimilarityCheck extends AbstractCheck { 33 | private final Queue nameHistory = EvictingQueue.create(this.epicGuard.config().nameSimilarityCheck().historySize()); 34 | private final LevenshteinDistance distanceAlgorithm = LevenshteinDistance.getDefaultInstance(); 35 | 36 | public NameSimilarityCheck(EpicGuard epicGuard) { 37 | super(epicGuard, epicGuard.messages().disconnect().nameSimilarity(), epicGuard.config().nameSimilarityCheck().priority()); 38 | } 39 | 40 | @Override 41 | public boolean isDetected(@NotNull ConnectingUser user) { 42 | synchronized (this.nameHistory) { 43 | for (String nick : this.nameHistory) { 44 | if (nick.equals(user.nickname())) { 45 | return false; // ignore identical nickname. 46 | } 47 | 48 | int distance = this.distanceAlgorithm.apply(nick, user.nickname()); 49 | if (distance <= this.epicGuard.config().nameSimilarityCheck().distance()) { 50 | return this.evaluate(this.epicGuard.config().nameSimilarityCheck().checkMode(), true); 51 | } 52 | } 53 | 54 | this.nameHistory.add(user.nickname()); 55 | return false; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/check/NicknameCheck.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.check; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.check.AbstractCheck; 20 | import me.xneox.epicguard.core.user.ConnectingUser; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | /** 24 | * This check tries to match the user's nickname with the configured regex pattern. 25 | */ 26 | public class NicknameCheck extends AbstractCheck { 27 | public NicknameCheck(EpicGuard epicGuard) { 28 | super(epicGuard, epicGuard.messages().disconnect().nickname(), epicGuard.config().nicknameCheck().priority()); 29 | } 30 | 31 | @Override 32 | public boolean isDetected(@NotNull ConnectingUser user) { 33 | return this.evaluate(this.epicGuard.config().nicknameCheck().checkMode(), 34 | user.nickname().matches(this.epicGuard.config().nicknameCheck().expression())); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/check/ProxyCheck.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.check; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.check.AbstractCheck; 20 | import me.xneox.epicguard.core.user.ConnectingUser; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | /** 24 | * This checks if the user is using a VPN or a proxy. 25 | * The detection logic is located in {@link me.xneox.epicguard.core.proxy.ProxyManager} 26 | */ 27 | public class ProxyCheck extends AbstractCheck { 28 | public ProxyCheck(EpicGuard epicGuard) { 29 | super(epicGuard, epicGuard.messages().disconnect().proxy(), epicGuard.config().proxyCheck().priority()); 30 | } 31 | 32 | @Override 33 | public boolean isDetected(@NotNull ConnectingUser user) { 34 | return this.evaluate(this.epicGuard.config().proxyCheck().checkMode(), 35 | this.epicGuard.proxyManager().isProxy(user.address())); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/check/ReconnectCheck.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.check; 17 | 18 | import java.util.Collection; 19 | import java.util.HashSet; 20 | import me.xneox.epicguard.core.EpicGuard; 21 | import me.xneox.epicguard.core.check.AbstractCheck; 22 | import me.xneox.epicguard.core.user.ConnectingUser; 23 | import org.jetbrains.annotations.NotNull; 24 | 25 | /** 26 | * This check forces player to reconnect if they are connecting for the first time. 27 | */ 28 | public class ReconnectCheck extends AbstractCheck { 29 | private final Collection connectingUserCache = new HashSet<>(); //todo: thread safety :/ 30 | 31 | public ReconnectCheck(EpicGuard epicGuard) { 32 | super(epicGuard, epicGuard.messages().disconnect().reconnect(), epicGuard.config().reconnectCheck().priority()); 33 | } 34 | 35 | @Override 36 | public boolean isDetected(@NotNull ConnectingUser user) { 37 | return this.evaluate(this.epicGuard.config().reconnectCheck().checkMode(), this.needsReconnect(user)); 38 | } 39 | 40 | private boolean needsReconnect(ConnectingUser connectingUser) { 41 | if (!this.connectingUserCache.contains(connectingUser)) { 42 | this.connectingUserCache.add(connectingUser); 43 | return true; 44 | } 45 | return false; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/check/ServerListCheck.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.check; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.check.AbstractCheck; 20 | import me.xneox.epicguard.core.user.ConnectingUser; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | /** 24 | * This check forces the user has to ping the server before joining. 25 | */ 26 | public class ServerListCheck extends AbstractCheck { 27 | public ServerListCheck(EpicGuard epicGuard) { 28 | super(epicGuard, epicGuard.messages().disconnect().serverListPing(), epicGuard.config().serverListCheck().priority()); 29 | } 30 | 31 | @Override 32 | public boolean isDetected(@NotNull ConnectingUser user) { 33 | return this.evaluate(this.epicGuard.config().serverListCheck().checkMode(), 34 | !this.epicGuard.storageManager().pingCache().contains(user.address())); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/command/CommandHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.command; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collection; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | import me.xneox.epicguard.core.EpicGuard; 23 | import me.xneox.epicguard.core.command.sub.AnalyzeCommand; 24 | import me.xneox.epicguard.core.command.sub.BlacklistCommand; 25 | import me.xneox.epicguard.core.command.sub.HelpCommand; 26 | import me.xneox.epicguard.core.command.sub.ReloadCommand; 27 | import me.xneox.epicguard.core.command.sub.SaveCommand; 28 | import me.xneox.epicguard.core.command.sub.StatusCommand; 29 | import me.xneox.epicguard.core.command.sub.WhitelistCommand; 30 | import me.xneox.epicguard.core.util.TextUtils; 31 | import me.xneox.epicguard.core.util.VersionUtils; 32 | import net.kyori.adventure.audience.Audience; 33 | import org.jetbrains.annotations.NotNull; 34 | 35 | /** 36 | * This class holds all registered subcommands, and handles the user command/tab suggestion input. 37 | * TODO: Better command system 38 | */ 39 | public class CommandHandler { 40 | private final Map commandMap = new HashMap<>(); 41 | private final EpicGuard epicGuard; 42 | 43 | public CommandHandler(EpicGuard epicGuard) { 44 | this.epicGuard = epicGuard; 45 | 46 | this.commandMap.put("analyze", new AnalyzeCommand()); 47 | this.commandMap.put("blacklist", new BlacklistCommand()); 48 | this.commandMap.put("help", new HelpCommand()); 49 | this.commandMap.put("reload", new ReloadCommand()); 50 | this.commandMap.put("status", new StatusCommand()); 51 | this.commandMap.put("whitelist", new WhitelistCommand()); 52 | this.commandMap.put("save", new SaveCommand()); 53 | } 54 | 55 | public void handleCommand(@NotNull String[] args, @NotNull Audience audience) { 56 | // No arguments provided - send the version message. 57 | if (args.length < 1) { 58 | audience.sendMessage(TextUtils.component("cff00 You are running EpicGuard v" + VersionUtils.CURRENT_VERSION + 59 | " on " + this.epicGuard.platform().platformVersion())); 60 | audience.sendMessage(TextUtils.component("cff00 Run &l/guard help cff00to see available commands and statistics")); 61 | return; 62 | } 63 | 64 | var subCommand = this.commandMap.get(args[0]); 65 | if (subCommand == null) { 66 | audience.sendMessage(TextUtils.component(this.epicGuard.messages().command().prefix() + this.epicGuard.messages().command().unknownCommand())); 67 | return; 68 | } 69 | 70 | subCommand.execute(audience, args, this.epicGuard); 71 | } 72 | 73 | @NotNull 74 | public Collection handleSuggestions(@NotNull String[] args) { 75 | // If no argument is specified, send all available subcommands. 76 | if (args.length <= 1) { 77 | return this.commandMap.keySet(); 78 | } 79 | 80 | var subCommand = this.commandMap.get(args[0]); 81 | if (subCommand != null) { 82 | return subCommand.suggest(args, this.epicGuard); 83 | } 84 | return new ArrayList<>(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/command/SubCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.command; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collection; 20 | import me.xneox.epicguard.core.EpicGuard; 21 | import net.kyori.adventure.audience.Audience; 22 | import org.jetbrains.annotations.NotNull; 23 | 24 | /** 25 | * A subcommand of the /epicguard command. 26 | */ 27 | public interface SubCommand { 28 | 29 | /** 30 | * Handles the execution of this subcommand 31 | * 32 | * @param audience the executor of this subcommand 33 | * @param args arguments provided by the executor 34 | * @param epicGuard instance of {@link EpicGuard} 35 | */ 36 | void execute(@NotNull Audience audience, @NotNull String[] args, @NotNull EpicGuard epicGuard); 37 | 38 | /** 39 | * Handles the tab-completion of this subcommand. 40 | * Returns available suggestions if possible. 41 | * 42 | * @param args arguments provided by the executor 43 | * @param epicGuard instance of {@link EpicGuard} 44 | * @return available suggestions, or an empty ArrayList 45 | */ 46 | @NotNull 47 | default Collection suggest(@NotNull String[] args, @NotNull EpicGuard epicGuard) { 48 | return new ArrayList<>(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/command/sub/AnalyzeCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.command.sub; 17 | 18 | import com.google.common.net.InetAddresses; 19 | import java.util.Collection; 20 | import me.xneox.epicguard.core.EpicGuard; 21 | import me.xneox.epicguard.core.command.SubCommand; 22 | import me.xneox.epicguard.core.config.MessagesConfiguration; 23 | import me.xneox.epicguard.core.storage.AddressMeta; 24 | import me.xneox.epicguard.core.util.TextUtils; 25 | import net.kyori.adventure.audience.Audience; 26 | import org.jetbrains.annotations.NotNull; 27 | 28 | public class AnalyzeCommand implements SubCommand { 29 | 30 | @SuppressWarnings("UnstableApiUsage") 31 | @Override 32 | public void execute(@NotNull Audience audience, @NotNull String[] args, @NotNull EpicGuard epicGuard) { 33 | var config = epicGuard.messages().command(); 34 | 35 | if (args.length != 2) { 36 | audience.sendMessage(TextUtils.component(config.prefix() + 37 | config.usage().replace("{USAGE}", "/guard analyze "))); 38 | return; 39 | } 40 | 41 | var meta = epicGuard.storageManager().resolveAddressMeta(args[1]); 42 | if (meta == null) { 43 | audience.sendMessage(TextUtils.component(config.prefix() + config.invalidArgument())); 44 | return; 45 | } 46 | 47 | // Assume that executor provided an address as the argument. 48 | String address = args[1]; 49 | 50 | // If executor provided nickname as the argument instead, we have to find their IP address. 51 | if (!InetAddresses.isInetAddress(args[1])) { 52 | for (var entry : epicGuard.storageManager().addresses().entrySet()) { 53 | if (entry.getValue().equals(meta)) { 54 | address = entry.getKey(); 55 | break; 56 | } 57 | } 58 | } 59 | 60 | for (String line : config.analyzeCommand()) { 61 | audience.sendMessage(TextUtils.component(line 62 | .replace("{ADDRESS}", address) 63 | .replace("{COUNTRY}", epicGuard.geoManager().countryCode(address)) 64 | .replace("{CITY}", epicGuard.geoManager().city(address)) 65 | .replace("{WHITELISTED}", meta.whitelisted() ? "&a✔" : "&c✖") 66 | .replace("{BLACKLISTED}", meta.blacklisted() ? "&a✔" : "&c✖") 67 | .replace("{ACCOUNT-AMOUNT}", String.valueOf(meta.nicknames().size())) 68 | .replace("{NICKNAMES}", String.join(", ", meta.nicknames())))); 69 | } 70 | } 71 | 72 | @Override 73 | public @NotNull Collection suggest(@NotNull String[] args, @NotNull EpicGuard epicGuard) { 74 | return epicGuard.storageManager().addresses().keySet(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/command/sub/BlacklistCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.command.sub; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.command.SubCommand; 20 | import me.xneox.epicguard.core.storage.AddressMeta; 21 | import me.xneox.epicguard.core.util.TextUtils; 22 | import net.kyori.adventure.audience.Audience; 23 | import org.jetbrains.annotations.NotNull; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Arrays; 27 | import java.util.Collection; 28 | 29 | public class BlacklistCommand implements SubCommand { 30 | @Override 31 | public void execute(@NotNull Audience audience, @NotNull String[] args, @NotNull EpicGuard epicGuard) { 32 | var config = epicGuard.messages().command(); 33 | 34 | if (args.length != 3) { 35 | audience.sendMessage(TextUtils.component(config.prefix() + config.usage() 36 | .replace("{USAGE}", "/guard blacklist "))); 37 | return; 38 | } 39 | 40 | var meta = epicGuard.storageManager().resolveAddressMeta(args[2]); 41 | if (meta == null) { 42 | audience.sendMessage(TextUtils.component(config.prefix() + config.invalidArgument())); 43 | return; 44 | } 45 | 46 | if (args[1].equalsIgnoreCase("add")) { 47 | if (meta.blacklisted()) { 48 | audience.sendMessage(TextUtils.component(config.prefix() + config.alreadyBlacklisted().replace("{USER}", args[2]))); 49 | return; 50 | } 51 | 52 | meta.blacklisted(true); 53 | audience.sendMessage(TextUtils.component(config.prefix() + config.blacklistAdd().replace("{USER}", args[2]))); 54 | } else if (args[1].equalsIgnoreCase("remove")) { 55 | if (!meta.blacklisted()) { 56 | audience.sendMessage(TextUtils.component(config.prefix() + config.notBlacklisted().replace("{USER}", args[2]))); 57 | return; 58 | } 59 | 60 | meta.blacklisted(false); 61 | audience.sendMessage(TextUtils.component(config.prefix() + config.blacklistRemove().replace("{USER}", args[2]))); 62 | } 63 | } 64 | 65 | @Override 66 | public @NotNull Collection suggest(@NotNull String[] args, @NotNull EpicGuard epicGuard) { 67 | if (args.length == 2) { 68 | return Arrays.asList("add", "remove"); 69 | } 70 | 71 | if (args[1].equalsIgnoreCase("remove")) { 72 | return epicGuard.storageManager().viewAddresses(AddressMeta::blacklisted); 73 | } 74 | return new ArrayList<>(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/command/sub/HelpCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.command.sub; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.command.SubCommand; 20 | import me.xneox.epicguard.core.storage.AddressMeta; 21 | import me.xneox.epicguard.core.util.TextUtils; 22 | import me.xneox.epicguard.core.util.VersionUtils; 23 | import net.kyori.adventure.audience.Audience; 24 | import org.jetbrains.annotations.NotNull; 25 | 26 | public class HelpCommand implements SubCommand { 27 | @Override 28 | public void execute(@NotNull Audience audience, @NotNull String[] args, @NotNull EpicGuard epicGuard) { 29 | for (String line : epicGuard.messages().command().mainCommand()) { 30 | audience.sendMessage(TextUtils.component(line 31 | .replace("{VERSION}", VersionUtils.CURRENT_VERSION) 32 | .replace("{BLACKLISTED-IPS}", String.valueOf(epicGuard.storageManager().viewAddresses(AddressMeta::blacklisted).size())) 33 | .replace("{WHITELISTED-IPS}", String.valueOf(epicGuard.storageManager().viewAddresses(AddressMeta::whitelisted).size())) 34 | .replace("{CPS}", String.valueOf(epicGuard.attackManager().connectionCounter())) 35 | .replace("{ATTACK}", epicGuard.attackManager().isUnderAttack() ? "&a✔" : "&c✖"))); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/command/sub/ReloadCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.command.sub; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.command.SubCommand; 20 | import me.xneox.epicguard.core.config.MessagesConfiguration; 21 | import me.xneox.epicguard.core.util.TextUtils; 22 | import net.kyori.adventure.audience.Audience; 23 | import org.jetbrains.annotations.NotNull; 24 | 25 | public class ReloadCommand implements SubCommand { 26 | @Override 27 | public void execute(@NotNull Audience audience, @NotNull String[] args, @NotNull EpicGuard epicGuard) { 28 | var config = epicGuard.messages().command(); 29 | 30 | epicGuard.loadConfigurations(); 31 | audience.sendMessage(TextUtils.component(config.prefix() + config.reloaded())); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/command/sub/SaveCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.command.sub; 17 | 18 | import java.sql.SQLException; 19 | import me.xneox.epicguard.core.EpicGuard; 20 | import me.xneox.epicguard.core.command.SubCommand; 21 | import me.xneox.epicguard.core.util.LogUtils; 22 | import me.xneox.epicguard.core.util.TextUtils; 23 | import net.kyori.adventure.audience.Audience; 24 | import org.jetbrains.annotations.NotNull; 25 | 26 | public class SaveCommand implements SubCommand { 27 | @Override 28 | public void execute(@NotNull Audience audience, @NotNull String[] args, @NotNull EpicGuard epicGuard) { 29 | try { 30 | epicGuard.storageManager().database().save(); 31 | audience.sendMessage(TextUtils.component(epicGuard.messages().command().prefix() + "&aData has been saved succesfully.")); 32 | } catch (SQLException ex) { 33 | audience.sendMessage(TextUtils.component(epicGuard.messages().command().prefix() + 34 | "&cAn exception ocurred when saving data. See console for details.")); 35 | LogUtils.catchException("Could not save data to the SQL database (command-induced)", ex); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/command/sub/StatusCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.command.sub; 17 | 18 | import java.util.Optional; 19 | import java.util.UUID; 20 | import me.xneox.epicguard.core.EpicGuard; 21 | import me.xneox.epicguard.core.command.SubCommand; 22 | import me.xneox.epicguard.core.user.OnlineUser; 23 | import me.xneox.epicguard.core.util.TextUtils; 24 | import net.kyori.adventure.audience.Audience; 25 | import net.kyori.adventure.identity.Identity; 26 | import net.kyori.adventure.text.Component; 27 | import net.kyori.adventure.text.format.TextColor; 28 | import org.jetbrains.annotations.NotNull; 29 | 30 | public class StatusCommand implements SubCommand { 31 | @Override 32 | public void execute(@NotNull Audience audience, @NotNull String[] args, @NotNull EpicGuard epicGuard) { 33 | var config = epicGuard.messages().command(); 34 | 35 | // for some reason not working in Velocity 36 | if (!audience.pointers().supports(Identity.UUID)) { 37 | audience.sendMessage(Component 38 | .text("This command is unavailable in the current environment.") 39 | .color(TextColor.fromHexString("#ff6600"))); 40 | return; 41 | } 42 | 43 | Optional uuidOptional = audience.pointers().get(Identity.UUID); 44 | uuidOptional.ifPresent(uuid -> { 45 | // UUID is present, enable notifications. 46 | OnlineUser onlineUser = epicGuard.userManager().getOrCreate(uuid); 47 | onlineUser.notifications(!onlineUser.notifications()); 48 | audience.sendMessage(TextUtils.component(config.prefix() + config.toggleStatus())); 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/command/sub/WhitelistCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.command.sub; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Arrays; 20 | import java.util.Collection; 21 | import me.xneox.epicguard.core.EpicGuard; 22 | import me.xneox.epicguard.core.command.SubCommand; 23 | import me.xneox.epicguard.core.config.MessagesConfiguration; 24 | import me.xneox.epicguard.core.storage.AddressMeta; 25 | import me.xneox.epicguard.core.util.TextUtils; 26 | import net.kyori.adventure.audience.Audience; 27 | import org.jetbrains.annotations.NotNull; 28 | 29 | public class WhitelistCommand implements SubCommand { 30 | @Override 31 | public void execute(@NotNull Audience audience, @NotNull String[] args, @NotNull EpicGuard epicGuard) { 32 | var config = epicGuard.messages().command(); 33 | 34 | if (args.length != 3) { 35 | audience.sendMessage(TextUtils.component(config.prefix() + config.usage() 36 | .replace("{USAGE}", "/guard whitelist "))); 37 | return; 38 | } 39 | 40 | var meta = epicGuard.storageManager().resolveAddressMeta(args[2]); 41 | if (meta == null) { 42 | audience.sendMessage(TextUtils.component(config.prefix() + config.invalidArgument())); 43 | return; 44 | } 45 | 46 | if (args[1].equalsIgnoreCase("add")) { 47 | if (meta.whitelisted()) { 48 | audience.sendMessage(TextUtils.component(config.prefix() + config.alreadyWhitelisted().replace("{USER}", args[2]))); 49 | return; 50 | } 51 | 52 | meta.whitelisted(true); 53 | audience.sendMessage(TextUtils.component(config.prefix() + config.whitelistAdd().replace("{USER}", args[2]))); 54 | } else if (args[1].equalsIgnoreCase("remove")) { 55 | if (!meta.whitelisted()) { 56 | audience.sendMessage(TextUtils.component(config.prefix() + config.notWhitelisted().replace("{USER}", args[2]))); 57 | return; 58 | } 59 | 60 | meta.whitelisted(false); 61 | audience.sendMessage(TextUtils.component(config.prefix() + config.whitelistRemove().replace("{USER}", args[2]))); 62 | } 63 | } 64 | 65 | @Override 66 | public @NotNull Collection suggest(@NotNull String[] args, @NotNull EpicGuard epicGuard) { 67 | if (args.length == 2) { 68 | return Arrays.asList("add", "remove"); 69 | } 70 | 71 | if (args[1].equalsIgnoreCase("remove")) { 72 | return epicGuard.storageManager().viewAddresses(AddressMeta::whitelisted); 73 | } 74 | return new ArrayList<>(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/config/MessagesConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.config; 17 | 18 | import java.util.Arrays; 19 | import java.util.List; 20 | import org.spongepowered.configurate.objectmapping.ConfigSerializable; 21 | 22 | @SuppressWarnings("ALL") // make intellij shut up about using final fields that would break the config loader. 23 | @ConfigSerializable 24 | public class MessagesConfiguration { 25 | 26 | // Config sections. 27 | private Command command = new Command(); 28 | private Disconnect disconnect = new Disconnect(); 29 | 30 | private String actionbarMonitor = "&cEpicGuard &8// &6%cps% &7connections/s &8| %status%"; 31 | private String actionbarNoAttack = "&7No attack..."; 32 | private String actionbarAttack = "&cAttack detected!"; 33 | private String updateAvailable = "A new update is available: {NEWVER} (You are still on {OLDVER})"; 34 | 35 | public Command command() { 36 | return this.command; 37 | } 38 | 39 | public Disconnect disconnect() { 40 | return this.disconnect; 41 | } 42 | 43 | public String actionbarMonitor() { 44 | return this.actionbarMonitor; 45 | } 46 | 47 | public String actionbarNoAttack() { 48 | return this.actionbarNoAttack; 49 | } 50 | 51 | public String actionbarAttack() { 52 | return this.actionbarAttack; 53 | } 54 | 55 | public String updateAvailable() { 56 | return this.updateAvailable; 57 | } 58 | 59 | @ConfigSerializable 60 | public static class Command { 61 | private String prefix = " &cEpicGuard &8// &7"; 62 | private String usage = "&cCorrect usage: &6{USAGE}"; 63 | private String unknownCommand = "&cUnknown command, use &6/epicguard &cfor available commands."; 64 | private String whitelistAdd = "&7The user &a{USER} &7has been added to the whitelist."; 65 | private String whitelistRemove = "The user &6{USER} &7has been removed from the whitelist"; 66 | private String blacklistAdd = "&7The user &c{USER} &7has been added to the blacklist."; 67 | private String blacklistRemove = "&7The user &6{USER} &7has been removed from the blacklist."; 68 | private String alreadyWhitelisted = "&cThe user &6{USER} &cis already whitelisted!"; 69 | private String alreadyBlacklisted = "&cThe user &6{USER} &cis already blacklisted!"; 70 | private String notWhitelisted = "&cThe user &6{USER} &cis not in whitelist!"; 71 | private String notBlacklisted = "&cThe user &6{USER} &cis not in the blacklist!"; 72 | private String reloaded = "&7Succesfully reloaded config and messages!"; 73 | private String toggleStatus = "&7You have toggled your attack status!"; 74 | private String invalidArgument = "&cCould not resolve address for this nickname, or provided address is invalid."; 75 | 76 | private List mainCommand = 77 | Arrays.asList( 78 | "", 79 | " &6EpicGuard Protection System &8- &7Running version &f{VERSION}", 80 | "", 81 | " &8▸ &7Under attack: {ATTACK}", 82 | " &8▸ &7Connections: &e{CPS}/s", 83 | " &8▸ &7Blacklist: &e{BLACKLISTED-IPS} &7IPs", 84 | " &8▸ &7Whitelist: &e{WHITELISTED-IPS} &7IPs", 85 | "", 86 | " &8/&fguard status &8- &7Toggle attack status on actionbar.", 87 | " &8/&fguard reload &8- &7Reload config and messages.", 88 | " &8/&fguard save &8- &7Save data to the database.", 89 | " &8/&fguard analyze &8- &7Perform detailed analysis on specified user.", 90 | " &8/&fguard whitelist &8- &7Whitelist/unwhitelist an address or nickname.", 91 | " &8/&fguard blacklist &8- &7Blacklist/unblacklist an address or nickname.", 92 | ""); 93 | 94 | private List analyzeCommand = 95 | Arrays.asList( 96 | "", 97 | " &6EpicGuard Analysis System &8- &7Results for &f{ADDRESS}", 98 | "", 99 | " &eGeographic Data:", 100 | " &8▸ &7Country: &f{COUNTRY}", 101 | " &8▸ &7City: &f{CITY}", 102 | "", 103 | " &eKnown Accounts&6 ({ACCOUNT-AMOUNT}):", 104 | " &8▸ &f{NICKNAMES}", 105 | "", 106 | " &eOther Data:", 107 | " &8▸ &7Whitelisted: {WHITELISTED}", 108 | " &8▸ &7Blacklisted: {BLACKLISTED}", 109 | ""); 110 | 111 | public String prefix() { 112 | return this.prefix; 113 | } 114 | 115 | public String usage() { 116 | return this.usage; 117 | } 118 | 119 | public String unknownCommand() { 120 | return this.unknownCommand; 121 | } 122 | 123 | public String whitelistAdd() { 124 | return this.whitelistAdd; 125 | } 126 | 127 | public String whitelistRemove() { 128 | return this.whitelistRemove; 129 | } 130 | 131 | public String blacklistAdd() { 132 | return this.blacklistAdd; 133 | } 134 | 135 | public String blacklistRemove() { 136 | return this.blacklistRemove; 137 | } 138 | 139 | public String alreadyWhitelisted() { 140 | return this.alreadyWhitelisted; 141 | } 142 | 143 | public String alreadyBlacklisted() { 144 | return this.alreadyBlacklisted; 145 | } 146 | 147 | public String notWhitelisted() { 148 | return this.notWhitelisted; 149 | } 150 | 151 | public String notBlacklisted() { 152 | return this.notBlacklisted; 153 | } 154 | 155 | public String reloaded() { 156 | return this.reloaded; 157 | } 158 | 159 | public String toggleStatus() { 160 | return this.toggleStatus; 161 | } 162 | 163 | public String invalidArgument() { 164 | return this.invalidArgument; 165 | } 166 | 167 | public List mainCommand() { 168 | return this.mainCommand; 169 | } 170 | 171 | public List analyzeCommand() { 172 | return this.analyzeCommand; 173 | } 174 | } 175 | 176 | @ConfigSerializable 177 | public static class Disconnect { 178 | private List geographical = Arrays.asList( 179 | "&8» &7You have been kicked by &bAntiBot Protection&7:", 180 | "&8» &cYour country/city is not allowed on this server."); 181 | 182 | private List blacklisted = Arrays.asList( 183 | "&8» &7You have been kicked by &bAntiBot Protection&7:", 184 | "&8» &cYou have been blacklisted on this server."); 185 | 186 | private List attackLockdown = Arrays.asList( 187 | "&8» &7You have been kicked by &bAntiBot Protection&7:", 188 | "&8» &cServer is under attack, please wait some seconds before joining."); 189 | 190 | private List proxy = Arrays.asList( 191 | "&8» &7You have been kicked by &bAntiBot Protection&7:", 192 | "&8» &cYou are using VPN or Proxy."); 193 | 194 | private List reconnect = Arrays.asList( 195 | "&8» &7You have been kicked by &bAntiBot Protection&7:", 196 | "&8» &cJoin the server again."); 197 | 198 | private List nickname = Arrays.asList( 199 | "&8» &7You have been kicked by &bAntiBot Protection&7:", 200 | "&8» &cYou nickname is not allowed on this server."); 201 | 202 | private List accountLimit = Arrays.asList( 203 | "&8» &7You have been kicked by &bAntiBot Protection&7:", 204 | "&8» &cYou have too many accounts on your IP address."); 205 | 206 | private List serverListPing = Arrays.asList( 207 | "&8» &7You have been kicked by &bAntiBot Protection&7:", 208 | "&8» &cYou must add our server to your servers list to verify yourself."); 209 | 210 | private List nameSimilarity = Arrays.asList( 211 | "&8» &7You have been kicked by &bAntiBot Protection&7:", 212 | "&8» &cYour nickname is too similar to other users connecting to the server."); 213 | 214 | private List settingsPacket = Arrays.asList( 215 | "&8» &7You have been kicked by &bAntiBot Protection&7:", 216 | "&8» &cBot-like behaviour detected, please join the server again."); 217 | 218 | public List geographical() { 219 | return this.geographical; 220 | } 221 | 222 | public List blacklisted() { 223 | return this.blacklisted; 224 | } 225 | 226 | public List attackLockdown() { 227 | return this.attackLockdown; 228 | } 229 | 230 | public List proxy() { 231 | return this.proxy; 232 | } 233 | 234 | public List reconnect() { 235 | return this.reconnect; 236 | } 237 | 238 | public List nickname() { 239 | return this.nickname; 240 | } 241 | 242 | public List accountLimit() { 243 | return this.accountLimit; 244 | } 245 | 246 | public List serverListPing() { 247 | return this.serverListPing; 248 | } 249 | 250 | public List nameSimilarity() { 251 | return this.nameSimilarity; 252 | } 253 | 254 | public List settingsPacket() { 255 | return this.settingsPacket; 256 | } 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/config/PluginConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.config; 17 | 18 | import java.util.Arrays; 19 | import java.util.List; 20 | import java.util.regex.Pattern; 21 | import me.xneox.epicguard.core.util.ToggleState; 22 | import me.xneox.epicguard.core.proxy.ProxyService; 23 | import org.spongepowered.configurate.objectmapping.ConfigSerializable; 24 | import org.spongepowered.configurate.objectmapping.meta.Comment; 25 | 26 | @SuppressWarnings("ALL") // make intellij shut up about using final fields that would break the config loader. 27 | @ConfigSerializable 28 | public class PluginConfiguration { 29 | 30 | @Comment("GeographicalCheck will filter countries/cities your players can connect from.") 31 | private Geographical geographical = new Geographical(); 32 | 33 | @Comment("Detect users who are connecting using proxies or VPNs.") 34 | private ProxyCheck proxyCheck = new ProxyCheck(); 35 | 36 | @Comment("This check will limit how many accounts can be registered from single IP address") 37 | private AccountLimitCheck accountLimitCheck = new AccountLimitCheck(); 38 | 39 | @Comment("Every vanilla client sends the Settings packet shortly after joining.\n" 40 | + "Some bots doesn't do this, and this check will try to detect that.") 41 | private SettingsCheck settingsCheck = new SettingsCheck(); 42 | 43 | @Comment("Nickname-check will block players if their nickname matches\n" 44 | + "the regex expression set below.") 45 | private NicknameCheck nicknameCheck = new NicknameCheck(); 46 | 47 | @Comment("NameSimilarityCheck will detect similar nicknames of the connecting users\n" 48 | + "(!) Experimental! https://neox.gitbook.io/epicguard-wiki/configuring/name-similarity-check") 49 | private NameSimilarityCheck nameSimilarityCheck = new NameSimilarityCheck(); 50 | 51 | @Comment("ReconnectCheck will force new users to join the server again.") 52 | private ReconnectCheck reconnectCheck = new ReconnectCheck(); 53 | 54 | @Comment("Server-list check will force users to add your server\n" 55 | + "to their server list (send a ping) before joining") 56 | private ServerListCheck serverListCheck = new ServerListCheck(); 57 | 58 | @Comment("If a player is online for long enough (see option below)\n" 59 | + "He will be added to the whitelist, and be exempt from every future detections") 60 | private AutoWhitelist autoWhitelist = new AutoWhitelist(); 61 | 62 | private ConsoleFilter consoleFilter = new ConsoleFilter(); 63 | private Misc misc = new Misc(); 64 | private Storage storage = new Storage(); 65 | 66 | @ConfigSerializable 67 | public static class Geographical { 68 | @Comment(""" 69 | NEVER - check is disabled. 70 | ATTACK - check will be performed only during bot-attack. 71 | ALWAYS - check will be always performed.""") 72 | private ToggleState checkMode = ToggleState.NEVER; 73 | 74 | @Comment(""" 75 | Checks with bigger priority will be executed before the checks with lower priority. 76 | (!) Requires a restart. 77 | """) 78 | private int priority = 7; 79 | 80 | @Comment(""" 81 | This will define if the 'countries' list should be a blacklist or a whitelist. 82 | true - configured countries are blocked 83 | false - only configured countries are allowed""") 84 | private boolean isBlacklist = false; 85 | 86 | @Comment("List of country codes: https://dev.maxmind.com/geoip/legacy/codes/iso3166/") 87 | private List countries = Arrays.asList("US", "DE"); 88 | 89 | @Comment("If a player tries to connect from city listed here, he will be blocked.") 90 | private List cityBlacklist = Arrays.asList("ExampleCity", "AnotherCity"); 91 | 92 | public ToggleState checkMode() { 93 | return this.checkMode; 94 | } 95 | 96 | public int priority() { 97 | return this.priority; 98 | } 99 | 100 | public boolean isBlacklist() { 101 | return this.isBlacklist; 102 | } 103 | 104 | public List countries() { 105 | return this.countries; 106 | } 107 | 108 | public List cityBlacklist() { 109 | return this.cityBlacklist; 110 | } 111 | } 112 | 113 | @ConfigSerializable 114 | public static class ProxyCheck { 115 | @Comment(""" 116 | NEVER - check is disabled. 117 | ATTACK - check will be performed only during bot-attack. 118 | ALWAYS - check will be always performed.""") 119 | private ToggleState checkMode = ToggleState.ALWAYS; 120 | 121 | @Comment(""" 122 | Checks with bigger priority will be executed before the checks with lower priority. 123 | (!) Requires a restart. 124 | """) 125 | private int priority = 1; 126 | 127 | @Comment(""" 128 | You can set as many proxy checking services as you want here. 129 | If you're not familiar with regex, see https://regexr.com/ or https://regex101.com/ 130 | For example, (yes|VPN) will check if the response contains either 'yes' or 'VPN'""") 131 | private List registeredServices = Arrays.asList( 132 | new ProxyService("https://proxycheck.io/v2/{IP}?key=PROXYCHECK_KEY&risk=1&vpn=1", Pattern.compile("(yes|VPN)"))); 133 | 134 | @Comment(""" 135 | How long in SECONDS responses from proxy check should be cached? 136 | Higher value increases performance, but keep in mind that if user 137 | disables their VPN but the cache hasn't expired yet, he will still be detected.""") 138 | private int cacheDuration = 300; 139 | 140 | public ToggleState checkMode() { 141 | return this.checkMode; 142 | } 143 | 144 | public int priority() { 145 | return this.priority; 146 | } 147 | 148 | public List services() { 149 | return this.registeredServices; 150 | } 151 | 152 | public int cacheDuration() { 153 | return this.cacheDuration; 154 | } 155 | } 156 | 157 | @ConfigSerializable 158 | public static class AccountLimitCheck { 159 | @Comment(""" 160 | NEVER - check is disabled. 161 | ATTACK - check will be performed only during bot-attack. 162 | ALWAYS - check will be always performed.""") 163 | private ToggleState checkMode = ToggleState.ALWAYS; 164 | 165 | @Comment(""" 166 | Checks with bigger priority will be executed before the checks with lower priority. 167 | (!) Requires a restart. 168 | """) 169 | private int priority = 3; 170 | 171 | @Comment("Limit of accounts per one IP address.") 172 | private int limit = 3; 173 | 174 | public ToggleState checkMode() { 175 | return this.checkMode; 176 | } 177 | 178 | public int priority() { 179 | return this.priority; 180 | } 181 | 182 | public int accountLimit() { 183 | return this.limit; 184 | } 185 | } 186 | 187 | @ConfigSerializable 188 | public static class SettingsCheck { 189 | @Comment("Enable or disable this check.") 190 | private boolean enabled = true; 191 | 192 | @Comment( 193 | "Delay in seconds after which we check if the player has already sent this packet.\n" 194 | + "Increase for faster detection, decrease if detecting players with bad internet connection") 195 | private int delay = 5; 196 | 197 | public boolean enabled() { 198 | return this.enabled; 199 | } 200 | 201 | public int delay() { 202 | return this.delay; 203 | } 204 | } 205 | 206 | @ConfigSerializable 207 | public static class NicknameCheck { 208 | @Comment(""" 209 | NEVER - check is disabled. 210 | ATTACK - check will be performed only during bot-attack. 211 | ALWAYS - check will be always performed.""") 212 | private ToggleState checkMode = ToggleState.ALWAYS; 213 | 214 | @Comment(""" 215 | Checks with bigger priority will be executed before the checks with lower priority. 216 | (!) Requires a restart. 217 | """) 218 | private int priority = 8; 219 | 220 | @Comment( 221 | "Default value will check if the nickname contains 'bot' or 'mcdown'.\n" 222 | + "You can use https://regex101.com/ for making and testing your own expression.") 223 | private String expression = "(?i).*(bot|mcdown).*"; 224 | 225 | public ToggleState checkMode() { 226 | return this.checkMode; 227 | } 228 | 229 | public int priority() { 230 | return this.priority; 231 | } 232 | 233 | public String expression() { 234 | return this.expression; 235 | } 236 | } 237 | 238 | @ConfigSerializable 239 | public static class NameSimilarityCheck { 240 | @Comment(""" 241 | NEVER - check is disabled. 242 | ATTACK - check will be performed only during bot-attack. 243 | ALWAYS - check will be always performed.""") 244 | private ToggleState checkMode = ToggleState.NEVER; 245 | 246 | @Comment(""" 247 | Checks with bigger priority will be executed before the checks with lower priority. 248 | (!) Requires a restart. 249 | """) 250 | private int priority = 2; 251 | 252 | @Comment(""" 253 | How many nicknames should be keep in the history? 254 | When an user is connecting to the server, his nickname will be added to the history. 255 | Then the nickname will be compared with other nicknames stored in the history. 256 | (!) Requires restart to apply.""") 257 | private int historySize = 5; 258 | 259 | @Comment(""" 260 | The lower the distance, the similar the names. 261 | If the distance detected is lower or same as configured here, 262 | it will be considered as a positive detection. 263 | Values below 1 are ignored, as it means identical name.""") 264 | private int distance = 1; 265 | 266 | public ToggleState checkMode() { 267 | return this.checkMode; 268 | } 269 | 270 | public int priority() { 271 | return this.priority; 272 | } 273 | 274 | public int historySize() { 275 | return this.historySize; 276 | } 277 | 278 | public int distance() { 279 | return this.distance; 280 | } 281 | } 282 | 283 | @ConfigSerializable 284 | public static class ReconnectCheck { 285 | @Comment(""" 286 | NEVER - check is disabled. 287 | ATTACK - check will be performed only during bot-attack. 288 | ALWAYS - check will be always performed.""") 289 | private ToggleState checkMode = ToggleState.ATTACK; 290 | 291 | @Comment(""" 292 | Checks with bigger priority will be executed before the checks with lower priority. 293 | (!) Requires a restart. 294 | """) 295 | private int priority = 4; 296 | 297 | public ToggleState checkMode() { 298 | return this.checkMode; 299 | } 300 | 301 | public int priority() { 302 | return this.priority; 303 | } 304 | } 305 | 306 | @ConfigSerializable 307 | public static class ServerListCheck { 308 | @Comment(""" 309 | NEVER - check is disabled. 310 | ATTACK - check will be performed only during bot-attack. 311 | ALWAYS - check will be always performed.""") 312 | private ToggleState checkMode = ToggleState.ATTACK; 313 | 314 | @Comment(""" 315 | Checks with bigger priority will be executed before the checks with lower priority. 316 | (!) Requires a restart. 317 | """) 318 | private int priority = 5; 319 | 320 | public ToggleState checkMode() { 321 | return this.checkMode; 322 | } 323 | 324 | public int priority() { 325 | return this.priority; 326 | } 327 | } 328 | 329 | @ConfigSerializable 330 | public static class ConsoleFilter { 331 | @Comment(""" 332 | Change when the console-filter should be active. 333 | NEVER - feature is disabled. 334 | ATTACK - feature will work only during bot-attack. 335 | ALWAYS - feature will always work.""") 336 | private ToggleState filterMode = ToggleState.ATTACK; 337 | 338 | @Comment("If log message contains one of these words, it will\n" 339 | + "be hidden. This can save a lot of CPU on big attacks.") 340 | private List filterMessages = 341 | Arrays.asList( 342 | "GameProfile", 343 | "Disconnected", 344 | "UUID of player", 345 | "logged in", 346 | "lost connection", 347 | "InitialHandler"); 348 | 349 | public ToggleState filterMode() { 350 | return this.filterMode; 351 | } 352 | 353 | public List filterMessages() { 354 | return this.filterMessages; 355 | } 356 | } 357 | 358 | @ConfigSerializable 359 | public static class AutoWhitelist { 360 | @Comment("Enable automatic whitelisting of the user's address.") 361 | private boolean enabled = false; 362 | 363 | @Comment("Time in seconds the player must be online\n" + 364 | "to be added to the EpicGuard's whitelist.") 365 | private int timeOnline = 600; 366 | 367 | public boolean enabled() { 368 | return this.enabled; 369 | } 370 | 371 | public int timeOnline() { 372 | return this.timeOnline; 373 | } 374 | } 375 | 376 | @ConfigSerializable 377 | public static class Misc { 378 | @Comment(""" 379 | Should every user (except if he is whitelisted) 380 | be disconnected when there is an bot attack? 381 | true - Better protection and HUGE performance boost 382 | false - Allow NEW players connecting during attack.""") 383 | private boolean lockdownOnAttack = true; 384 | 385 | @Comment("How many connections per second must be made,\n" 386 | + "to activate the attack mode temporally?") 387 | private int attackConnectionThreshold = 6; 388 | 389 | @Comment(""" 390 | How often (in seconds) the plugin should check if amount of connections 391 | is slower than 'attack-connection-treshold' and disable attack mode? 392 | (!) Requires restart to apply.""") 393 | private long attackResetInterval = 80L; 394 | 395 | @Comment("Set to false to disable update checker.") 396 | private boolean updateChecker = true; 397 | 398 | @Comment("Time in minutes before auto-saving data.\n" + 399 | "(!) Requires restart to apply.") 400 | private long autoSaveInterval = 10L; 401 | 402 | @Comment("Enabling this will log additional useful information, such as performed detections.") 403 | private boolean debug = false; 404 | 405 | public boolean lockdownOnAttack() { 406 | return this.lockdownOnAttack; 407 | } 408 | 409 | public int attackConnectionThreshold() { 410 | return this.attackConnectionThreshold; 411 | } 412 | 413 | public long attackResetInterval() { 414 | return this.attackResetInterval; 415 | } 416 | 417 | public boolean updateChecker() { 418 | return this.updateChecker; 419 | } 420 | 421 | public long autoSaveInterval() { 422 | return this.autoSaveInterval; 423 | } 424 | 425 | public boolean debug() { 426 | return this.debug; 427 | } 428 | } 429 | 430 | @ConfigSerializable 431 | public static class Storage { 432 | 433 | @Comment(""" 434 | false - use SQLite for storage 435 | true - use MYSQL for storage 436 | (!) This option requires a restart. Changing storage type will reset your current data.""") 437 | private boolean useMysql = false; 438 | 439 | private String host = "127.0.0.1"; 440 | private int port = 3306; 441 | private String database = "database!"; 442 | private String user = "username!"; 443 | private String password = "password!"; 444 | 445 | public boolean useMySQL() { 446 | return this.useMysql; 447 | } 448 | 449 | public String host() { 450 | return this.host; 451 | } 452 | 453 | public int port() { 454 | return this.port; 455 | } 456 | 457 | public String database() { 458 | return this.database; 459 | } 460 | 461 | public String user() { 462 | return this.user; 463 | } 464 | 465 | public String password() { 466 | return this.password; 467 | } 468 | } 469 | 470 | // ======================== 471 | // GETTERS 472 | // ======================== 473 | 474 | public Geographical geographical() { 475 | return this.geographical; 476 | } 477 | 478 | public ProxyCheck proxyCheck() { 479 | return this.proxyCheck; 480 | } 481 | 482 | public AccountLimitCheck accountLimitCheck() { 483 | return this.accountLimitCheck; 484 | } 485 | 486 | public SettingsCheck settingsCheck() { 487 | return this.settingsCheck; 488 | } 489 | 490 | public NicknameCheck nicknameCheck() { 491 | return this.nicknameCheck; 492 | } 493 | 494 | public NameSimilarityCheck nameSimilarityCheck() { 495 | return this.nameSimilarityCheck; 496 | } 497 | 498 | public ReconnectCheck reconnectCheck() { 499 | return this.reconnectCheck; 500 | } 501 | 502 | public ServerListCheck serverListCheck() { 503 | return this.serverListCheck; 504 | } 505 | 506 | public ConsoleFilter consoleFilter() { 507 | return this.consoleFilter; 508 | } 509 | 510 | public AutoWhitelist autoWhitelist() { 511 | return this.autoWhitelist; 512 | } 513 | 514 | public Misc misc() { 515 | return this.misc; 516 | } 517 | 518 | public Storage storage() { 519 | return this.storage; 520 | } 521 | } 522 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/handler/DisconnectHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.handler; 17 | 18 | import java.util.UUID; 19 | import me.xneox.epicguard.core.EpicGuard; 20 | import me.xneox.epicguard.core.user.OnlineUser; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | /** 24 | * Handler for the PlayerQuit/Disconnect listeners. 25 | * Used for removing the {@link OnlineUser} instance from cache. 26 | */ 27 | public abstract class DisconnectHandler { 28 | private final EpicGuard epicGuard; 29 | 30 | public DisconnectHandler(EpicGuard epicGuard) { 31 | this.epicGuard = epicGuard; 32 | } 33 | 34 | /** 35 | * Handling the player who has been online but quit the server. 36 | * 37 | * @param uuid UUID of the (offline) player. 38 | */ 39 | public void onDisconnect(@NotNull UUID uuid) { 40 | this.epicGuard.userManager().removeUser(uuid); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/handler/PingHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.handler; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | /** 22 | * Handler for the ServerListPing listeners. Used by ServerListCheck to verify if the user has 23 | * pinged the server (added it to their list). 24 | */ 25 | public abstract class PingHandler { 26 | private final EpicGuard epicGuard; 27 | 28 | public PingHandler(EpicGuard epicGuard) { 29 | this.epicGuard = epicGuard; 30 | } 31 | 32 | /** 33 | * Handling the user who just pinged the server. 34 | * 35 | * @param address Address of the pinger. 36 | */ 37 | public void onPing(@NotNull String address) { 38 | this.epicGuard.storageManager().pingCache().add(address); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/handler/PostLoginHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.handler; 17 | 18 | import java.util.UUID; 19 | import me.xneox.epicguard.core.EpicGuard; 20 | import me.xneox.epicguard.core.storage.AddressMeta; 21 | import me.xneox.epicguard.core.user.OnlineUser; 22 | import me.xneox.epicguard.core.util.TextUtils; 23 | import org.jetbrains.annotations.NotNull; 24 | 25 | /** 26 | * Handler for the PlayerJoin or PostLogin listeners Used for the auto-whitelist feature, 27 | * and for SettingsCheck. 28 | */ 29 | public abstract class PostLoginHandler { 30 | private final EpicGuard epicGuard; 31 | 32 | public PostLoginHandler(EpicGuard epicGuard) { 33 | this.epicGuard = epicGuard; 34 | } 35 | 36 | /** 37 | * Handling the player who just have joined to the server. 38 | * 39 | * @param uuid UUID of the online player. 40 | * @param address Address of the online player. 41 | */ 42 | public void onPostLogin(@NotNull UUID uuid, @NotNull String address) { 43 | // Schedule a delayed task to whitelist the player. 44 | if (this.epicGuard.config().autoWhitelist().enabled()) { 45 | this.epicGuard.platform().runTaskLater(() -> { 46 | var user = this.epicGuard.userManager().get(uuid); 47 | 48 | // check if player has logged out 49 | if (user != null) { 50 | var meta = this.epicGuard.storageManager().addressMeta(address); 51 | meta.whitelisted(true); 52 | } 53 | }, this.epicGuard.config().autoWhitelist().timeOnline()); 54 | } 55 | 56 | // Schedule a delayed task to check if the player has sent the Settings packet. 57 | if (this.epicGuard.config().settingsCheck().enabled()) { 58 | this.epicGuard.platform().runTaskLater(() -> { 59 | var user = this.epicGuard.userManager().get(uuid); 60 | if (user != null && !user.settingsChanged()) { 61 | this.epicGuard.platform().disconnectUser(uuid, TextUtils.multilineComponent(this.epicGuard.messages().disconnect().settingsPacket())); 62 | } 63 | }, this.epicGuard.config().settingsCheck().delay()); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/handler/PreLoginHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.handler; 17 | 18 | import java.util.Optional; 19 | import java.util.Set; 20 | import java.util.TreeSet; 21 | import me.xneox.epicguard.core.EpicGuard; 22 | import me.xneox.epicguard.core.check.AbstractCheck; 23 | import me.xneox.epicguard.core.check.AccountLimitCheck; 24 | import me.xneox.epicguard.core.check.BlacklistCheck; 25 | import me.xneox.epicguard.core.check.GeographicalCheck; 26 | import me.xneox.epicguard.core.check.LockdownCheck; 27 | import me.xneox.epicguard.core.check.NameSimilarityCheck; 28 | import me.xneox.epicguard.core.check.NicknameCheck; 29 | import me.xneox.epicguard.core.check.ProxyCheck; 30 | import me.xneox.epicguard.core.check.ReconnectCheck; 31 | import me.xneox.epicguard.core.check.ServerListCheck; 32 | import me.xneox.epicguard.core.user.ConnectingUser; 33 | import me.xneox.epicguard.core.util.LogUtils; 34 | import net.kyori.adventure.text.TextComponent; 35 | import org.jetbrains.annotations.NotNull; 36 | 37 | /** 38 | * Handler for PreLogin listeners. It performs every antibot check (except SettingsCheck). 39 | */ 40 | public abstract class PreLoginHandler { 41 | private final Set pipeline = new TreeSet<>(); 42 | private final EpicGuard epicGuard; 43 | 44 | public PreLoginHandler(EpicGuard epicGuard) { 45 | this.epicGuard = epicGuard; 46 | 47 | // This will be automatically sorted based on the configured priority. 48 | pipeline.add(new LockdownCheck(epicGuard)); 49 | pipeline.add(new BlacklistCheck(epicGuard)); 50 | pipeline.add(new NicknameCheck(epicGuard)); 51 | pipeline.add(new GeographicalCheck(epicGuard)); 52 | pipeline.add(new ServerListCheck(epicGuard)); 53 | pipeline.add(new ReconnectCheck(epicGuard)); 54 | pipeline.add(new AccountLimitCheck(epicGuard)); 55 | pipeline.add(new NameSimilarityCheck(epicGuard)); 56 | pipeline.add(new ProxyCheck(epicGuard)); 57 | 58 | epicGuard.logger().info("Order of the detection pipeline: " + 59 | String.join(", ", this.pipeline.stream().map(check -> check.getClass().getSimpleName()).toList())); 60 | } 61 | 62 | /** 63 | * Handling the incoming connection, and returning an optional disconnect message. 64 | * 65 | * @param address Address of the connecting user. 66 | * @param nickname Nickname of the connecting user. 67 | * @return Disconnect message, or an empty Optional if undetected. 68 | */ 69 | @NotNull 70 | public Optional onPreLogin(@NotNull String address, @NotNull String nickname) { 71 | LogUtils.debug("Handling incoming connection: " + address + "/" + nickname); 72 | 73 | // Increment the connections per second and check if it's bigger than max-cps in config. 74 | if (this.epicGuard.attackManager().incrementConnectionCounter() >= this.epicGuard.config().misc().attackConnectionThreshold()) { 75 | this.epicGuard.logger().warn("Enabling attack-mode (" + this.epicGuard.attackManager().connectionCounter() + " connections/s)"); 76 | this.epicGuard.attackManager().attack(true); 77 | } 78 | 79 | // Check if the user is whitelisted, if yes, return empty result (undetected). 80 | if (this.epicGuard.storageManager().addressMeta(address).whitelisted()) { 81 | LogUtils.debug("Skipping whitelisted user: " + address + "/" + nickname); 82 | return Optional.empty(); 83 | } 84 | 85 | var user = new ConnectingUser(address, nickname); 86 | for (AbstractCheck check : this.pipeline) { 87 | if (check.isDetected(user)) { 88 | LogUtils.debug(nickname + "/" + address + " detected by " + check.getClass().getSimpleName()); 89 | return Optional.of(check.detectionMessage()); 90 | } 91 | } 92 | 93 | LogUtils.debug(nickname + "/" + address + " has passed all checks and is allowed to connect."); 94 | this.epicGuard.storageManager().updateAccounts(user); 95 | return Optional.empty(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/handler/SettingsHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.handler; 17 | 18 | import java.util.UUID; 19 | import me.xneox.epicguard.core.EpicGuard; 20 | import me.xneox.epicguard.core.user.OnlineUser; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | /** 24 | * If the user has sent the Settings packet, it will be marked on their {@link OnlineUser} instance. 25 | * Vanilla clients will send this packet shortly after joining the world. 26 | */ 27 | public abstract class SettingsHandler { 28 | private final EpicGuard epicGuard; 29 | 30 | public SettingsHandler(EpicGuard epicGuard) { 31 | this.epicGuard = epicGuard; 32 | } 33 | 34 | /** 35 | * Handling the online player who has changed their settings. Usually called shortly after joining 36 | * the game. 37 | * 38 | * @param uuid UUID of the online player. 39 | */ 40 | public void onSettingsChanged(@NotNull UUID uuid) { 41 | this.epicGuard.userManager().getOrCreate(uuid).settingsChanged(true); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/manager/AttackManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.manager; 17 | 18 | import java.util.concurrent.atomic.AtomicInteger; 19 | 20 | /** 21 | * This class holds variables related to the current server attack status. 22 | */ 23 | public class AttackManager { 24 | private final AtomicInteger connectionCounter = new AtomicInteger(); 25 | private boolean attack; 26 | 27 | /** 28 | * Attack-mode is a special temporary state, that indicates that the server is under attack. It 29 | * triggers when connection counter is above the threshold. 30 | * 31 | * @return State of the attack-mode 32 | */ 33 | public boolean isUnderAttack() { 34 | return this.attack; 35 | } 36 | 37 | public void attack(boolean attack) { 38 | this.attack = attack; 39 | } 40 | 41 | public int connectionCounter() { 42 | return this.connectionCounter.get(); 43 | } 44 | 45 | public void resetConnectionCounter() { 46 | this.connectionCounter.set(0); 47 | } 48 | 49 | /** 50 | * Increments the connection per second counter, and returns it's current value 51 | * 52 | * @return Current connections per second. 53 | */ 54 | public int incrementConnectionCounter() { 55 | return this.connectionCounter.incrementAndGet(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/manager/GeoManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.manager; 17 | 18 | import com.maxmind.db.CHMCache; 19 | import com.maxmind.geoip2.DatabaseReader; 20 | import com.maxmind.geoip2.exception.GeoIp2Exception; 21 | import java.io.File; 22 | import java.io.FileInputStream; 23 | import java.io.FileOutputStream; 24 | import java.io.IOException; 25 | import java.util.concurrent.TimeUnit; 26 | import java.util.zip.GZIPInputStream; 27 | import me.xneox.epicguard.core.EpicGuard; 28 | import me.xneox.epicguard.core.util.FileUtils; 29 | import me.xneox.epicguard.core.util.LogUtils; 30 | import me.xneox.epicguard.core.util.TextUtils; 31 | import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; 32 | import org.apache.commons.compress.utils.IOUtils; 33 | import org.jetbrains.annotations.NotNull; 34 | 35 | /** 36 | * This class manages the GeoLite2's databases, downloads and updates them if needed. It also 37 | * contains methods for easy database access. 38 | */ 39 | public class GeoManager { 40 | private final EpicGuard epicGuard; 41 | 42 | private DatabaseReader countryReader; 43 | private DatabaseReader cityReader; 44 | 45 | public GeoManager(EpicGuard epicGuard) { 46 | this.epicGuard = epicGuard; 47 | epicGuard.logger().info("This product includes GeoLite2 data created by MaxMind, available from https://www.maxmind.com"); 48 | 49 | var parent = new File(FileUtils.EPICGUARD_DIR, "/data"); 50 | //noinspection ResultOfMethodCallIgnored 51 | parent.mkdirs(); 52 | 53 | var countryDatabase = new File(parent, "GeoLite2-Country.mmdb"); 54 | var cityDatabase = new File(parent, "GeoLite2-City.mmdb"); 55 | 56 | var countryArchive = new File(parent, "GeoLite2-Country.tar.gz"); 57 | var cityArchive = new File(parent, "GeoLite2-City.tar.gz"); 58 | 59 | try { 60 | this.downloadDatabase( 61 | countryDatabase, 62 | countryArchive, 63 | "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=LARAgQo3Fw7W9ZMS&suffix=tar.gz"); 64 | this.downloadDatabase( 65 | cityDatabase, 66 | cityArchive, 67 | "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=LARAgQo3Fw7W9ZMS&suffix=tar.gz"); 68 | 69 | this.countryReader = new DatabaseReader.Builder(countryDatabase).withCache(new CHMCache()).build(); 70 | this.cityReader = new DatabaseReader.Builder(cityDatabase).withCache(new CHMCache()).build(); 71 | } catch (IOException ex) { 72 | LogUtils.catchException("Couldn't download the GeoIP databases, please check your internet connection.", ex); 73 | } 74 | } 75 | 76 | @SuppressWarnings("ResultOfMethodCallIgnored") 77 | private void downloadDatabase(@NotNull File database, @NotNull File archive, @NotNull String url) throws IOException { 78 | if (!database.exists() || System.currentTimeMillis() - database.lastModified() > TimeUnit.DAYS.toMillis(7L)) { 79 | // Database does not exist or is outdated, and need to be downloaded. 80 | this.epicGuard.logger().info("Downloading the GeoIP database file: " + database.getName()); 81 | FileUtils.downloadFile(url, archive); 82 | 83 | this.epicGuard.logger().info("Extracting the database from the tar archive..."); 84 | var tarInput = new TarArchiveInputStream(new GZIPInputStream(new FileInputStream(archive))); 85 | 86 | var entry = tarInput.getNextTarEntry(); 87 | while (entry != null) { 88 | // Extracting the database (.mmdb) database we are looking for. 89 | if (entry.getName().endsWith(database.getName())) { 90 | IOUtils.copy(tarInput, new FileOutputStream(database)); 91 | } 92 | 93 | entry = tarInput.getNextTarEntry(); 94 | } 95 | 96 | // Closing InputStream and removing archive file. 97 | tarInput.close(); 98 | archive.delete(); 99 | this.epicGuard.logger().info("Database (" + database.getName() + ") has been extracted succesfuly."); 100 | } 101 | } 102 | 103 | @NotNull 104 | public String countryCode(@NotNull String address) { 105 | var inetAddress = TextUtils.parseAddress(address); 106 | if (inetAddress != null && this.countryReader != null) { 107 | try { 108 | return this.countryReader.country(inetAddress).getCountry().getIsoCode(); 109 | } catch (IOException | GeoIp2Exception ex) { 110 | this.epicGuard.logger().warn("Couldn't find the country for the address " + address + ": " + ex.getMessage()); 111 | } 112 | } 113 | return "unknown"; 114 | } 115 | 116 | @NotNull 117 | public String city(@NotNull String address) { 118 | var inetAddress = TextUtils.parseAddress(address); 119 | if (inetAddress != null && this.cityReader != null) { 120 | try { 121 | return this.cityReader.city(inetAddress).getCity().getName(); 122 | } catch (IOException | GeoIp2Exception ex) { 123 | this.epicGuard.logger().warn("Couldn't find the city for the address " + address + ": " + ex.getMessage()); 124 | } 125 | } 126 | return "unknown"; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/manager/UserManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.manager; 17 | 18 | import java.util.Collection; 19 | import java.util.Map; 20 | import java.util.UUID; 21 | import java.util.concurrent.ConcurrentHashMap; 22 | import me.xneox.epicguard.core.user.OnlineUser; 23 | import org.jetbrains.annotations.NotNull; 24 | import org.jetbrains.annotations.Nullable; 25 | 26 | /** 27 | * This manager caches the {@link OnlineUser} for currently online players 28 | */ 29 | public class UserManager { 30 | private final Map userMap = new ConcurrentHashMap<>(); 31 | 32 | @NotNull 33 | public Collection users() { 34 | return this.userMap.values(); 35 | } 36 | 37 | /** 38 | * Returns the {@link OnlineUser} for the specified 39 | * UUID. Creates a new object if absent. 40 | */ 41 | @NotNull 42 | public OnlineUser getOrCreate(@NotNull UUID uuid) { 43 | return this.userMap.computeIfAbsent(uuid, OnlineUser::new); 44 | } 45 | 46 | /** 47 | * Returns the {@link OnlineUser} for the specified 48 | * UUID, or null if the user is offline. 49 | */ 50 | @Nullable 51 | public OnlineUser get(@NotNull UUID uuid) { 52 | return this.userMap.get(uuid); 53 | } 54 | 55 | public void removeUser(@NotNull UUID uuid) { 56 | this.userMap.remove(uuid); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/proxy/ProxyManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.proxy; 17 | 18 | import com.google.common.cache.Cache; 19 | import com.google.common.cache.CacheBuilder; 20 | import java.util.concurrent.TimeUnit; 21 | import me.xneox.epicguard.core.EpicGuard; 22 | import me.xneox.epicguard.core.util.LogUtils; 23 | import me.xneox.epicguard.core.util.URLUtils; 24 | import org.jetbrains.annotations.NotNull; 25 | 26 | /** 27 | * Performs requests to the registered ProxyServices and caches the results. 28 | */ 29 | public class ProxyManager { 30 | private final EpicGuard epicGuard; 31 | private final Cache resultCache; 32 | 33 | public ProxyManager(EpicGuard epicGuard) { 34 | this.epicGuard = epicGuard; 35 | this.resultCache = CacheBuilder.newBuilder() 36 | .expireAfterWrite(epicGuard.config().proxyCheck().cacheDuration(), TimeUnit.SECONDS) 37 | .build(); 38 | } 39 | 40 | /** 41 | * This method reads the response from all the registered ProxyServices until the detection is positive. 42 | * If the result is present in cache, the value from the cache will be returned instead. 43 | * 44 | * @param address The checked IP address. 45 | * @return Whenever the address is detected to be a proxy or not. 46 | */ 47 | public boolean isProxy(@NotNull String address) { 48 | return this.resultCache.asMap().computeIfAbsent(address, userIp -> { 49 | for (ProxyService service : this.epicGuard.config().proxyCheck().services()) { 50 | String url = service.url().replace("{IP}", userIp); 51 | LogUtils.debug("Sending request to: " + url); 52 | 53 | String response = URLUtils.readString(url); 54 | LogUtils.debug("Received response: " + response); 55 | 56 | if (response != null && service.matcher().matcher(response).find()) { 57 | return true; 58 | } 59 | } 60 | return false; 61 | }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/proxy/ProxyService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.proxy; 17 | 18 | import java.util.regex.Pattern; 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | /** 22 | * Represents a service used for proxy detection. 23 | */ 24 | public record ProxyService(@NotNull String url, @NotNull Pattern matcher) { 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/proxy/ProxyServiceSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.proxy; 17 | 18 | import java.lang.reflect.Type; 19 | import java.util.regex.Pattern; 20 | import org.checkerframework.checker.nullness.qual.Nullable; 21 | import org.spongepowered.configurate.ConfigurationNode; 22 | import org.spongepowered.configurate.serialize.SerializationException; 23 | import org.spongepowered.configurate.serialize.TypeSerializer; 24 | 25 | /** 26 | * Configurate serializer and deserializer for the configured {@link ProxyService}. 27 | */ 28 | public class ProxyServiceSerializer implements TypeSerializer { 29 | public static final ProxyServiceSerializer INSTANCE = new ProxyServiceSerializer(); 30 | 31 | @Override 32 | public ProxyService deserialize(Type type, ConfigurationNode node) throws SerializationException { 33 | var urlNode = node.node("url"); 34 | String url = urlNode.getString(); 35 | 36 | var matcherNode = node.node("matcher"); 37 | String matcher = matcherNode.getString(); 38 | 39 | if (url == null || matcher == null) { 40 | throw new SerializationException("Invalid proxy-services configuration."); 41 | } 42 | return new ProxyService(url, Pattern.compile(matcher)); 43 | } 44 | 45 | @Override 46 | public void serialize(Type type, @Nullable ProxyService service, ConfigurationNode target) throws SerializationException { 47 | if (service == null) { 48 | target.raw(null); 49 | return; 50 | } 51 | 52 | target.node("url").set(service.url()); 53 | target.node("matcher").set(service.matcher().pattern()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/storage/AddressMeta.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.storage; 17 | 18 | import java.util.List; 19 | import java.util.Objects; 20 | import org.jetbrains.annotations.NotNull; 21 | 22 | /** 23 | * AddressMeta holds information about an IP address. 24 | * All known AddressMeta's are stored in the database and cached in the {@link StorageManager} 25 | */ 26 | public class AddressMeta { 27 | private final List nicknames; 28 | private boolean blacklisted; 29 | private boolean whitelisted; 30 | 31 | public AddressMeta(boolean blacklisted, boolean whitelisted, @NotNull List nicknames) { 32 | this.blacklisted = blacklisted; 33 | this.whitelisted = whitelisted; 34 | this.nicknames = nicknames; 35 | } 36 | 37 | public boolean blacklisted() { 38 | return this.blacklisted; 39 | } 40 | 41 | public void blacklisted(boolean blacklisted) { 42 | this.blacklisted = blacklisted; 43 | } 44 | 45 | public boolean whitelisted() { 46 | return this.whitelisted; 47 | } 48 | 49 | public void whitelisted(boolean whitelisted) { 50 | this.whitelisted = whitelisted; 51 | } 52 | 53 | @NotNull 54 | public List nicknames() { 55 | return this.nicknames; 56 | } 57 | 58 | @Override 59 | public boolean equals(Object o) { 60 | if (this == o) { 61 | return true; 62 | } 63 | if (o == null || getClass() != o.getClass()) { 64 | return false; 65 | } 66 | AddressMeta that = (AddressMeta) o; 67 | return blacklisted == that.blacklisted && whitelisted == that.whitelisted 68 | && Objects.equals(nicknames, that.nicknames); 69 | } 70 | 71 | @Override 72 | public int hashCode() { 73 | return Objects.hash(nicknames, blacklisted, whitelisted); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/storage/Database.java: -------------------------------------------------------------------------------- 1 | package me.xneox.epicguard.core.storage; 2 | 3 | import com.zaxxer.hikari.HikariConfig; 4 | import com.zaxxer.hikari.HikariDataSource; 5 | import java.io.File; 6 | import java.sql.SQLException; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.Map; 10 | import me.xneox.epicguard.core.EpicGuard; 11 | import me.xneox.epicguard.core.util.FileUtils; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | public class Database { 15 | private final EpicGuard core; 16 | private HikariDataSource source; 17 | 18 | public Database(@NotNull EpicGuard core) { 19 | this.core = core; 20 | } 21 | 22 | // Initial connection to the database, obtaining HikariDataSource. 23 | public void connect() throws SQLException, ClassNotFoundException { 24 | var config = this.core.config().storage(); 25 | var hikariConfig = new HikariConfig(); 26 | 27 | if (config.useMySQL()) { 28 | Class.forName("com.mysql.cj.jdbc.Driver"); // Driver is not loaded on Velocity 29 | 30 | hikariConfig.setJdbcUrl("jdbc:mysql://" + config.host() + ":" + config.port() + "/" + config.database()); 31 | hikariConfig.setUsername(config.user()); 32 | hikariConfig.setPassword(config.password()); 33 | 34 | hikariConfig.addDataSourceProperty("cachePrepStmts", true); 35 | hikariConfig.addDataSourceProperty("prepStmtCacheSize", 250); 36 | hikariConfig.addDataSourceProperty("prepStmtCacheSqlLimit", 2048); 37 | hikariConfig.addDataSourceProperty("useServerPrepStmts", true); 38 | } else { 39 | var file = FileUtils.create(new File(FileUtils.EPICGUARD_DIR, "database.db")); 40 | 41 | Class.forName("org.sqlite.JDBC"); // Driver is not loaded on Waterfall/Velocity 42 | hikariConfig.setJdbcUrl("jdbc:sqlite:" + file.getPath()); 43 | } 44 | 45 | // Enable leak detection when debug is enabled. 46 | if (this.core.config().misc().debug()) { 47 | hikariConfig.setLeakDetectionThreshold(30000); 48 | } 49 | 50 | this.source = new HikariDataSource(hikariConfig); 51 | } 52 | 53 | // Creating default table and reading addresses from the database. 54 | public void load() throws SQLException { 55 | try (var connection = this.source.getConnection(); var statement = connection.prepareStatement( 56 | "CREATE TABLE IF NOT EXISTS epicguard_addresses(" 57 | + "`address` VARCHAR(255) NOT NULL PRIMARY KEY, " 58 | + "`blacklisted` BOOLEAN NOT NULL, " 59 | + "`whitelisted` BOOLEAN NOT NULL, " 60 | + "`nicknames` TEXT NOT NULL" 61 | + ")")) { 62 | statement.executeUpdate(); 63 | } 64 | 65 | try (var connection = this.source.getConnection(); var statement = connection.prepareStatement("SELECT * FROM epicguard_addresses"); 66 | var rs = statement.executeQuery()) { 67 | 68 | while (rs.next()) { 69 | var meta = new AddressMeta( 70 | rs.getBoolean("blacklisted"), 71 | rs.getBoolean("whitelisted"), 72 | new ArrayList<>(Arrays.asList(rs.getString("nicknames").split(",")))); 73 | 74 | this.core.storageManager().addresses().put(rs.getString("address"), meta); 75 | } 76 | } 77 | } 78 | 79 | // Saving cached addresses to the database. 80 | public void save() throws SQLException { 81 | for (Map.Entry entry : this.core.storageManager().addresses().entrySet()) { 82 | var meta = entry.getValue(); 83 | 84 | try (var connection = this.source.getConnection(); var statement = connection.prepareStatement( 85 | "REPLACE INTO" 86 | + " epicguard_addresses(address, blacklisted, whitelisted, nicknames)" 87 | + " VALUES(?, ?, ?, ?)")) { 88 | 89 | statement.setString(1, entry.getKey()); 90 | statement.setBoolean(2, meta.blacklisted()); 91 | statement.setBoolean(3, meta.whitelisted()); 92 | statement.setString(4, String.join(",", meta.nicknames())); 93 | 94 | statement.executeUpdate(); 95 | } 96 | } 97 | } 98 | 99 | // Shut down the Hikari connection pool. 100 | public void shutdown() { 101 | this.source.close(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/storage/StorageManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.storage; 17 | 18 | import com.google.common.net.InetAddresses; 19 | import java.util.ArrayList; 20 | import java.util.Collection; 21 | import java.util.HashSet; 22 | import java.util.List; 23 | import java.util.Map; 24 | import java.util.concurrent.ConcurrentHashMap; 25 | import java.util.function.Predicate; 26 | import me.xneox.epicguard.core.EpicGuard; 27 | import me.xneox.epicguard.core.user.ConnectingUser; 28 | import me.xneox.epicguard.core.util.LogUtils; 29 | import org.jetbrains.annotations.NotNull; 30 | import org.jetbrains.annotations.Nullable; 31 | 32 | /** 33 | * This class caches all known {@link AddressMeta}'s and performs various operations on them. 34 | */ 35 | public class StorageManager { 36 | private final Map addresses = new ConcurrentHashMap<>(); 37 | private final Collection pingCache = new HashSet<>(); 38 | private final Database database; 39 | 40 | public StorageManager(EpicGuard epicGuard) { 41 | this.database = new Database(epicGuard); 42 | } 43 | 44 | public void setupDatabase() { 45 | try { 46 | this.database.connect(); 47 | this.database.load(); 48 | } catch (Exception exception) { 49 | LogUtils.catchException("Could not connect to the database. Check if your connection is configured correctly.", exception); 50 | } 51 | } 52 | 53 | /** 54 | * Returns an {@link AddressMeta} for the specified address. Creates a new AddressMeta if it 55 | * doesen't exist for this address. 56 | */ 57 | @NotNull 58 | public AddressMeta addressMeta(@NotNull String address) { 59 | return this.addresses.computeIfAbsent(address, s -> new AddressMeta(false, false, new ArrayList<>())); 60 | } 61 | 62 | /** 63 | * When an address is specified: 64 | * - Redirects to the {@link #addressMeta(String)} method. 65 | * - Never returns null. 66 | * 67 | * When a nickname is specified: 68 | * - Tries to detect last used address by this nickname. 69 | * - If found, redirects to the {@link #addressMeta(String)} method. 70 | * - If not found, returns null. 71 | */ 72 | @Nullable 73 | public AddressMeta resolveAddressMeta(@NotNull String value) { 74 | //noinspection UnstableApiUsage 75 | String address = InetAddresses.isInetAddress(value) ? value : lastSeenAddress(value); 76 | return address != null ? addressMeta(address) : null; 77 | } 78 | 79 | /** 80 | * Searches for the last used address of the specified nickname. 81 | */ 82 | @Nullable 83 | public String lastSeenAddress(@NotNull String nickname) { 84 | return this.addresses.entrySet().stream() 85 | .filter(entry -> entry.getValue().nicknames().stream().anyMatch(nick -> nick.equalsIgnoreCase(nickname))) 86 | .findFirst() 87 | .map(Map.Entry::getKey) 88 | .orElse(null); 89 | } 90 | 91 | /** 92 | * Checks if the address meta of connecting user contains his current nickname. 93 | * If absent, it is added. 94 | */ 95 | public void updateAccounts(@NotNull ConnectingUser user) { 96 | var accounts = this.addressMeta(user.address()).nicknames(); 97 | if (!accounts.contains(user.nickname())) { 98 | accounts.add(user.nickname()); 99 | } 100 | } 101 | 102 | /** 103 | * A legacy method for viewing addresses that meet a specific condition. For example, this can 104 | * return whitelisted or blacklisted addresses. 105 | * 106 | * Returned list is immutable, used only for statistics and command suggestions. 107 | */ 108 | @NotNull 109 | public List viewAddresses(@NotNull Predicate predicate) { 110 | return this.addresses.entrySet().stream() 111 | .filter(entry -> predicate.test(entry.getValue())) 112 | .map(Map.Entry::getKey) 113 | .toList(); 114 | } 115 | 116 | @NotNull 117 | public Map addresses() { 118 | return this.addresses; 119 | } 120 | 121 | @NotNull 122 | public Database database() { 123 | return this.database; 124 | } 125 | 126 | @NotNull 127 | public Collection pingCache() { 128 | return this.pingCache; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/task/AttackResetTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.task; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | 20 | /** 21 | * This task disables attack-mode if the connections per seconds are lower than configured. 22 | */ 23 | public record AttackResetTask(EpicGuard epicGuard) implements Runnable { 24 | 25 | @Override 26 | public void run() { 27 | if (this.epicGuard.attackManager().connectionCounter() < this.epicGuard.config().misc().attackConnectionThreshold()) { 28 | this.epicGuard.attackManager().attack(false); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/task/DataSaveTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.task; 17 | 18 | import java.sql.SQLException; 19 | import me.xneox.epicguard.core.EpicGuard; 20 | import me.xneox.epicguard.core.util.LogUtils; 21 | 22 | /** 23 | * This task saves data to the database. 24 | */ 25 | public record DataSaveTask(EpicGuard epicGuard) implements Runnable { 26 | 27 | @Override 28 | public void run() { 29 | try { 30 | this.epicGuard.storageManager().database().save(); 31 | } catch (SQLException exception) { 32 | LogUtils.catchException("Could not save data to the SQL database (save-task)", exception); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/task/MonitorTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.task; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.user.OnlineUser; 20 | import me.xneox.epicguard.core.util.TextUtils; 21 | 22 | /** 23 | * This task displays current attack status on the actionbar of users who enabled them. 24 | */ 25 | public record MonitorTask(EpicGuard epicGuard) implements Runnable { 26 | 27 | @Override 28 | public void run() { 29 | var config = this.epicGuard.messages(); 30 | var textComponent = TextUtils.component(config.actionbarMonitor() 31 | .replace("%cps%", String.valueOf(this.epicGuard.attackManager().connectionCounter())) 32 | .replace("%status%", this.epicGuard.attackManager().isUnderAttack() ? config.actionbarAttack() : config.actionbarNoAttack())); 33 | 34 | for (OnlineUser user : this.epicGuard.userManager().users()) { 35 | if (user.notifications()) { 36 | var audience = this.epicGuard.platform().audience(user.uuid()); 37 | if (audience != null) { 38 | audience.sendActionBar(textComponent); 39 | } 40 | } 41 | } 42 | 43 | // Because this task is repeating every second, we can reset the connections/s counter. 44 | this.epicGuard.attackManager().resetConnectionCounter(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/task/UpdateCheckerTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.task; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.util.VersionUtils; 20 | 21 | /** 22 | * This task checks for updates, and if a new version is found, it will be printed to the console. 23 | */ 24 | public record UpdateCheckerTask(EpicGuard epicGuard) implements Runnable { 25 | 26 | @Override 27 | public void run() { 28 | VersionUtils.checkForUpdates(latest -> 29 | this.epicGuard.logger().info(this.epicGuard.messages().updateAvailable() 30 | .replace("{NEWVER}", latest) 31 | .replace("{OLDVER}", VersionUtils.CURRENT_VERSION))); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/user/ConnectingUser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.user; 17 | 18 | import org.jetbrains.annotations.NotNull; 19 | 20 | /** 21 | * Represents a user who is currently connecting to the server. 22 | * It is also cached by some checks. 23 | */ 24 | public record ConnectingUser(@NotNull String address, @NotNull String nickname) { 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/user/OnlineUser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.user; 17 | 18 | import com.google.common.base.Objects; 19 | import java.util.UUID; 20 | import org.jetbrains.annotations.NotNull; 21 | 22 | /** 23 | * Represents a player who is currently connected to the server. 24 | */ 25 | public class OnlineUser { 26 | private final UUID uuid; 27 | private boolean notifications; 28 | private boolean settingsChanged; 29 | 30 | public OnlineUser(@NotNull UUID uuid) { 31 | this.uuid = uuid; 32 | } 33 | 34 | /** 35 | * @return the user's UUID. 36 | */ 37 | @NotNull 38 | public UUID uuid() { 39 | return this.uuid; 40 | } 41 | 42 | /** 43 | * @return whenever the user has enabled the status notifications. 44 | */ 45 | public boolean notifications() { 46 | return this.notifications; 47 | } 48 | 49 | public void notifications(boolean notifications) { 50 | this.notifications = notifications; 51 | } 52 | 53 | /** 54 | * @return whenever the user has sent the Settings packet at least once. 55 | */ 56 | public boolean settingsChanged() { 57 | return this.settingsChanged; 58 | } 59 | 60 | public void settingsChanged(boolean settingsChanged) { 61 | this.settingsChanged = settingsChanged; 62 | } 63 | 64 | @Override 65 | public boolean equals(Object o) { 66 | if (this == o) { 67 | return true; 68 | } 69 | if (o == null || getClass() != o.getClass()) { 70 | return false; 71 | } 72 | OnlineUser that = (OnlineUser) o; 73 | return Objects.equal(uuid, that.uuid); 74 | } 75 | 76 | @Override 77 | public int hashCode() { 78 | return Objects.hashCode(uuid); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/util/ConfigurationLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.util; 17 | 18 | import org.jetbrains.annotations.NotNull; 19 | import org.spongepowered.configurate.ConfigurateException; 20 | import org.spongepowered.configurate.hocon.HoconConfigurationLoader; 21 | import org.spongepowered.configurate.objectmapping.ObjectMapper; 22 | import org.spongepowered.configurate.serialize.SerializationException; 23 | 24 | /** 25 | * This class loads the configuration, maps values, and saves to the file. 26 | * 27 | * @param the configuration class 28 | */ 29 | public class ConfigurationLoader { 30 | private final HoconConfigurationLoader loader; 31 | private ObjectMapper mapper; 32 | 33 | public ConfigurationLoader(@NotNull Class implementation, @NotNull HoconConfigurationLoader loader) { 34 | this.loader = loader; 35 | 36 | try { 37 | this.mapper = ObjectMapper.factory().get(implementation); 38 | } catch (SerializationException ex) { 39 | LogUtils.catchException("Couldn't create the object mapper for configuration: " + implementation.getSimpleName(), ex); 40 | } 41 | } 42 | 43 | @NotNull 44 | public C load() throws ConfigurateException { 45 | var configuration = this.mapper.load(this.loader.load()); 46 | this.save(configuration); // write default values 47 | return configuration; 48 | } 49 | 50 | public void save(@NotNull C config) throws ConfigurateException { 51 | var node = this.loader.createNode(); 52 | this.mapper.save(config, node); 53 | this.loader.save(node); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/util/FileUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.util; 17 | 18 | import java.io.File; 19 | import java.io.FileOutputStream; 20 | import java.io.IOException; 21 | import java.nio.channels.Channels; 22 | import java.nio.channels.ReadableByteChannel; 23 | import me.xneox.epicguard.core.EpicGuardAPI; 24 | import org.apache.commons.lang3.Validate; 25 | import org.jetbrains.annotations.NotNull; 26 | 27 | /** 28 | * This util helps with managing files. 29 | */ 30 | public final class FileUtils { 31 | public static final String EPICGUARD_DIR = "plugins/EpicGuard"; 32 | 33 | @SuppressWarnings("ResultOfMethodCallIgnored") 34 | public static void downloadFile(@NotNull String urlFrom, @NotNull File file) throws IOException { 35 | EpicGuardAPI.INSTANCE.instance().logger().info("Downloading file from " + urlFrom + " to " + file.getAbsolutePath()); 36 | 37 | // Make sure the original file will be replaced, if it exists 38 | file.delete(); 39 | file.createNewFile(); 40 | 41 | var connection = URLUtils.openConnection(urlFrom); 42 | try (ReadableByteChannel channel = Channels.newChannel(connection.getInputStream()); 43 | var outputStream = new FileOutputStream(file)) { 44 | 45 | outputStream.getChannel().transferFrom(channel, 0, Long.MAX_VALUE); 46 | } 47 | } 48 | 49 | /** 50 | * Creates new file, catches eventual exception and logs to debug. 51 | * 52 | * @param file The file to be created. 53 | * @return The created file. 54 | */ 55 | @NotNull 56 | public static File create(@NotNull File file) { 57 | Validate.notNull(file, "Can't create null file!"); 58 | 59 | try { 60 | if (file.createNewFile()) { 61 | LogUtils.debug("Created new file: " + file.getPath()); 62 | } 63 | } catch (IOException e) { 64 | LogUtils.catchException("Can't create database file", e); 65 | } 66 | 67 | return file; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/util/LogUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.util; 17 | 18 | import me.xneox.epicguard.core.EpicGuardAPI; 19 | import org.jetbrains.annotations.NotNull; 20 | import org.slf4j.Logger; 21 | 22 | /** 23 | * This util helps with various logging operations. 24 | */ 25 | public final class LogUtils { 26 | private static final Logger LOGGER = EpicGuardAPI.INSTANCE.instance().logger(); 27 | 28 | /** 29 | * Catches a Throwable and prints a detailed error message. 30 | * 31 | * @param details details about where the error has occurred 32 | * @param throwable the caught exception 33 | */ 34 | public static void catchException(@NotNull String details, @NotNull Throwable throwable) { 35 | LOGGER.error("An error occurred in EpicGuard v" + VersionUtils.CURRENT_VERSION); 36 | if (VersionUtils.isUpdateAvailable()) { 37 | LOGGER.error(" (!) Your version is outdated. Update before sending bug report!"); 38 | } 39 | 40 | LOGGER.error(" > Details: " + details); 41 | LOGGER.error(" > Platform: " + EpicGuardAPI.INSTANCE.platformVersion()); 42 | LOGGER.error(" > Stacktrace: "); 43 | LOGGER.error("", throwable); 44 | } 45 | 46 | /** 47 | * Logs a message if debug is enabled in the configuration. 48 | * 49 | * @param message message to be logged 50 | */ 51 | public static void debug(@NotNull String message) { 52 | if (EpicGuardAPI.INSTANCE.instance().config().misc().debug()) { 53 | LOGGER.info("(Debug) " + message); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/util/TextUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.util; 17 | 18 | import java.net.InetAddress; 19 | import java.net.UnknownHostException; 20 | import java.util.List; 21 | import me.xneox.epicguard.core.EpicGuardAPI; 22 | import net.kyori.adventure.text.TextComponent; 23 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; 24 | import org.apache.commons.lang3.Validate; 25 | import org.jetbrains.annotations.NotNull; 26 | import org.jetbrains.annotations.Nullable; 27 | 28 | public final class TextUtils { 29 | private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer.builder() 30 | .character('&') 31 | .hexCharacter('#') 32 | .hexColors() 33 | .build(); 34 | 35 | /** 36 | * Constructs a {@link TextComponent} from legacy string. 37 | * Supports legacy color-codes by "&" and hex colors by "&#" 38 | * 39 | * @param message the original string 40 | * @return a component created from the string 41 | */ 42 | @NotNull 43 | public static TextComponent component(@NotNull String message) { 44 | return SERIALIZER.deserialize(message); 45 | } 46 | 47 | /** 48 | * Builds a multiline {@link TextComponent} from list of strings. 49 | */ 50 | @NotNull 51 | public static TextComponent multilineComponent(@NotNull List list) { 52 | Validate.notNull(list, "Kick message cannot be null!"); 53 | 54 | var builder = new StringBuilder(); 55 | for (String line : list) { 56 | builder.append(line).append("\n"); 57 | } 58 | return component(builder.toString()); 59 | } 60 | 61 | /** 62 | * Tries to parse an {@link InetAddress} from the provided string. 63 | * For more information, see {@link InetAddress#getByName(String)} 64 | * 65 | * @param address String representation of a hostname 66 | * @return the parsed InetAddress 67 | */ 68 | @Nullable 69 | public static InetAddress parseAddress(@NotNull String address) { 70 | try { 71 | return InetAddress.getByName(address); 72 | } catch (UnknownHostException ex) { 73 | EpicGuardAPI.INSTANCE.instance().logger().warn("Couldn't resolve the InetAddress for the host " + address + ": " + ex.getMessage()); 74 | } 75 | return null; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/util/ToggleState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.util; 17 | 18 | import me.xneox.epicguard.core.check.AbstractCheck; 19 | 20 | /** 21 | * Determines when an {@link AbstractCheck} should be performed. 22 | * Can be configured in the config for some checks. 23 | */ 24 | public enum ToggleState { 25 | NEVER, 26 | ALWAYS, 27 | ATTACK 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/util/URLUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.util; 17 | 18 | import java.io.IOException; 19 | import java.net.URL; 20 | import java.net.URLConnection; 21 | import java.nio.charset.StandardCharsets; 22 | import java.util.Scanner; 23 | import me.xneox.epicguard.core.EpicGuardAPI; 24 | import org.jetbrains.annotations.NotNull; 25 | import org.jetbrains.annotations.Nullable; 26 | 27 | /** 28 | * This util helps with performing URL requests. 29 | */ 30 | public final class URLUtils { 31 | @Nullable 32 | public static String readString(@NotNull String url) { 33 | try { 34 | var connection = openConnection(url); 35 | try (Scanner scanner = new Scanner(connection.getInputStream(), StandardCharsets.UTF_8.toString())) { 36 | scanner.useDelimiter("\\A"); 37 | return scanner.hasNext() ? scanner.next() : ""; 38 | } 39 | } catch (IOException exception) { 40 | EpicGuardAPI.INSTANCE.instance().logger().warn("Couldn't read the content of " + url + " [" + exception.getMessage() + "]"); 41 | } 42 | return null; 43 | } 44 | 45 | @NotNull 46 | public static URLConnection openConnection(@NotNull String url) throws IOException { 47 | var connection = new URL(url).openConnection(); 48 | connection.addRequestProperty("User-Agent", "Mozilla/4.0"); 49 | connection.setConnectTimeout(5000); 50 | connection.setReadTimeout(5000); 51 | return connection; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/util/VersionUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.util; 17 | 18 | import java.util.function.Consumer; 19 | import org.checkerframework.checker.nullness.qual.NonNull; 20 | import org.jetbrains.annotations.NotNull; 21 | 22 | /** 23 | * This util holds current EpicGuard version and checks for the latest available version. 24 | */ 25 | public final class VersionUtils { 26 | public static final String CURRENT_VERSION = "{version}"; // replaced by the blossom task. 27 | private static final String CHECK_URL = "https://raw.githubusercontent.com/xxneox/EpicGuard/master/VERSION.txt"; 28 | 29 | private static boolean updateAvailable; 30 | 31 | /** 32 | * Checks the latest version to see if there's any update available. 33 | * @param action Action to run when there's an update available. 34 | */ 35 | public static void checkForUpdates(@NotNull Consumer action) { 36 | String latest = URLUtils.readString(CHECK_URL); 37 | if (latest == null) { 38 | return; // a warning will be thrown by the URLUtils anyway. 39 | } 40 | 41 | var latestVersion = new Version(latest); 42 | var currentVersion = new Version(CURRENT_VERSION); 43 | 44 | // 1 means outdated, 0 means up-to-date, -1 means newer than released. 45 | if (latestVersion.compareTo(currentVersion) > 0) { 46 | updateAvailable = true; 47 | action.accept(latest); 48 | } 49 | } 50 | 51 | public static boolean isUpdateAvailable() { 52 | return updateAvailable; 53 | } 54 | 55 | /* 56 | @author brianguertin (https://gist.github.com/brianguertin/ada4b65c6d1c4f6d3eee3c12b6ce021b) 57 | */ 58 | public static class Version implements Comparable { 59 | public final int[] numbers; 60 | 61 | public Version(@NonNull String version) { 62 | var split = version.split("-")[0].split("\\."); 63 | numbers = new int[split.length]; 64 | for (int i = 0; i < split.length; i++) { 65 | numbers[i] = Integer.parseInt(split[i]); 66 | } 67 | } 68 | 69 | @Override 70 | public int compareTo(@NonNull Version another) { 71 | int maxLength = Math.max(numbers.length, another.numbers.length); 72 | for (int i = 0; i < maxLength; i++) { 73 | int left = i < numbers.length ? numbers[i] : 0; 74 | int right = i < another.numbers.length ? another.numbers[i] : 0; 75 | if (left != right) { 76 | return left < right ? -1 : 1; 77 | } 78 | } 79 | return 0; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /core/src/main/java/me/xneox/epicguard/core/util/logging/LogFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.core.util.logging; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.util.ToggleState; 20 | import org.apache.logging.log4j.Level; 21 | import org.apache.logging.log4j.LogManager; 22 | import org.apache.logging.log4j.Marker; 23 | import org.apache.logging.log4j.core.LogEvent; 24 | import org.apache.logging.log4j.core.Logger; 25 | import org.apache.logging.log4j.core.filter.AbstractFilter; 26 | import org.apache.logging.log4j.message.Message; 27 | 28 | /** 29 | * This class adds a Log4J filter. 30 | * Filtered messages can be configured in the configuration. 31 | */ 32 | public class LogFilter extends AbstractFilter { 33 | private final EpicGuard epicGuard; 34 | 35 | public LogFilter(EpicGuard epicGuard) { 36 | this.epicGuard = epicGuard; 37 | } 38 | 39 | public void register() { 40 | var logger = (Logger) LogManager.getRootLogger(); 41 | logger.addFilter(this); 42 | } 43 | 44 | @Override 45 | public Result filter(LogEvent event) { 46 | return event == null ? Result.NEUTRAL : isLoggable(event.getMessage().getFormattedMessage()); 47 | } 48 | 49 | @Override 50 | public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) { 51 | return isLoggable(msg.getFormattedMessage()); 52 | } 53 | 54 | @Override 55 | public Result filter(Logger logger, Level level, Marker marker, String msg, Object... params) { 56 | return isLoggable(msg); 57 | } 58 | 59 | @Override 60 | public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) { 61 | return msg == null ? Result.NEUTRAL : isLoggable(msg.toString()); 62 | } 63 | 64 | private Result isLoggable(String message) { 65 | var state = this.epicGuard.config().consoleFilter().filterMode(); 66 | if (state == ToggleState.ALWAYS || state == ToggleState.ATTACK && this.epicGuard.attackManager().isUnderAttack()) { 67 | for (String string : this.epicGuard.config().consoleFilter().filterMessages()) { 68 | if (message.contains(string)) { 69 | return Result.DENY; 70 | } 71 | } 72 | } 73 | return Result.NEUTRAL; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group = me.xneox 2 | version = 7.1.2 3 | 4 | org.gradle.caching=true 5 | org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awumii/EpicGuard/4ba79bc1ee31f904151ca9fdfaf4398b30312a5c/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionSha256Sum=9afb3ca688fc12c761a0e9e4321e4d24e977a4a8916c8a768b1fe05ddb4d6b66 -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | # JitPack uses JDK 8 by default, but JDK 16+ is required to compile this project. 2 | # Also the default build command is broken... 3 | before_install: 4 | - wget https://github.com/sormuras/bach/raw/master/install-jdk.sh 5 | - source install-jdk.sh --feature 17 6 | 7 | install: 8 | - chmod +x gradlew 9 | - ./gradlew publishToMavenLocal -------------------------------------------------------------------------------- /paper/build.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencies { 2 | implementation(project(":core")) 3 | compileOnly("io.papermc.paper:paper-api:1.17.1-R0.1-SNAPSHOT") 4 | } 5 | 6 | tasks { 7 | build { 8 | dependsOn(shadowJar) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /paper/src/main/java/me/xneox/epicguard/paper/EpicGuardPaper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.paper; 17 | 18 | import java.util.UUID; 19 | import me.xneox.epicguard.core.EpicGuard; 20 | import me.xneox.epicguard.core.Platform; 21 | import me.xneox.epicguard.paper.listener.PlayerPostLoginListener; 22 | import me.xneox.epicguard.paper.listener.PlayerPreLoginListener; 23 | import me.xneox.epicguard.paper.listener.PlayerQuitListener; 24 | import me.xneox.epicguard.paper.listener.PlayerSettingsListener; 25 | import me.xneox.epicguard.paper.listener.ServerPingListener; 26 | import net.kyori.adventure.audience.Audience; 27 | import net.kyori.adventure.text.Component; 28 | import org.bukkit.Bukkit; 29 | import org.bukkit.plugin.java.JavaPlugin; 30 | import org.jetbrains.annotations.NotNull; 31 | import org.jetbrains.annotations.Nullable; 32 | import org.slf4j.Logger; 33 | 34 | public class EpicGuardPaper extends JavaPlugin implements Platform { 35 | private EpicGuard epicGuard; 36 | 37 | @Override 38 | public void onEnable() { 39 | this.epicGuard = new EpicGuard(this); 40 | 41 | var pluginManager = Bukkit.getPluginManager(); 42 | pluginManager.registerEvents(new PlayerPreLoginListener(this.epicGuard), this); 43 | pluginManager.registerEvents(new PlayerQuitListener(this.epicGuard), this); 44 | pluginManager.registerEvents(new PlayerPostLoginListener(this.epicGuard), this); 45 | pluginManager.registerEvents(new ServerPingListener(this.epicGuard), this); 46 | pluginManager.registerEvents(new PlayerSettingsListener(this.epicGuard), this); 47 | 48 | var command = this.getCommand("epicguard"); 49 | if (command != null) { 50 | var handler = new PaperCommandHandler(this.epicGuard); 51 | command.setExecutor(handler); 52 | command.setTabCompleter(handler); 53 | } 54 | } 55 | 56 | @Override 57 | public void onDisable() { 58 | this.epicGuard.shutdown(); 59 | } 60 | 61 | @Override 62 | public @NotNull String platformVersion() { 63 | return Bukkit.getVersion(); 64 | } 65 | 66 | @Override 67 | public @NotNull Logger logger() { 68 | return this.getSLF4JLogger(); 69 | } 70 | 71 | @Override 72 | public @Nullable Audience audience(@NotNull UUID uuid) { 73 | return Bukkit.getPlayer(uuid); 74 | } 75 | 76 | @Override 77 | public void disconnectUser(@NotNull UUID uuid, @NotNull Component message) { 78 | var player = Bukkit.getPlayer(uuid); 79 | if (player != null) { 80 | player.kick(message); 81 | } 82 | } 83 | 84 | @Override 85 | public void runTaskLater(@NotNull Runnable task, long seconds) { 86 | Bukkit.getScheduler().runTaskLater(this, task, seconds * 20L); 87 | } 88 | 89 | @Override 90 | public void scheduleRepeatingTask(@NotNull Runnable task, long seconds) { 91 | Bukkit.getScheduler().runTaskTimerAsynchronously(this, task, 20L, seconds * 20L); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /paper/src/main/java/me/xneox/epicguard/paper/PaperCommandHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.paper; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import me.xneox.epicguard.core.EpicGuard; 21 | import me.xneox.epicguard.core.command.CommandHandler; 22 | import org.bukkit.command.Command; 23 | import org.bukkit.command.CommandExecutor; 24 | import org.bukkit.command.CommandSender; 25 | import org.bukkit.command.TabCompleter; 26 | import org.jetbrains.annotations.NotNull; 27 | import org.jetbrains.annotations.Nullable; 28 | 29 | public class PaperCommandHandler extends CommandHandler implements CommandExecutor, TabCompleter { 30 | public PaperCommandHandler(EpicGuard epicGuard) { 31 | super(epicGuard); 32 | } 33 | 34 | @Override 35 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { 36 | this.handleCommand(args, sender); 37 | return true; 38 | } 39 | 40 | @Override 41 | public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { 42 | return new ArrayList<>(this.handleSuggestions(args)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /paper/src/main/java/me/xneox/epicguard/paper/listener/PlayerPostLoginListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.paper.listener; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.handler.PostLoginHandler; 20 | import org.bukkit.event.EventHandler; 21 | import org.bukkit.event.Listener; 22 | import org.bukkit.event.player.PlayerJoinEvent; 23 | 24 | public class PlayerPostLoginListener extends PostLoginHandler implements Listener { 25 | public PlayerPostLoginListener(EpicGuard epicGuard) { 26 | super(epicGuard); 27 | } 28 | 29 | @EventHandler 30 | public void onJoin(PlayerJoinEvent event) { 31 | var player = event.getPlayer(); 32 | this.onPostLogin(player.getUniqueId(), player.getAddress().getAddress().getHostAddress()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /paper/src/main/java/me/xneox/epicguard/paper/listener/PlayerPreLoginListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.paper.listener; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.handler.PreLoginHandler; 20 | import org.bukkit.event.EventHandler; 21 | import org.bukkit.event.EventPriority; 22 | import org.bukkit.event.Listener; 23 | import org.bukkit.event.player.AsyncPlayerPreLoginEvent; 24 | 25 | public class PlayerPreLoginListener extends PreLoginHandler implements Listener { 26 | public PlayerPreLoginListener(EpicGuard epicGuard) { 27 | super(epicGuard); 28 | } 29 | 30 | @EventHandler(priority = EventPriority.LOWEST) 31 | public void onPreLogin(AsyncPlayerPreLoginEvent event) { 32 | String address = event.getAddress().getHostAddress(); 33 | String nickname = event.getName(); 34 | 35 | this.onPreLogin(address, nickname).ifPresent(result -> 36 | event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, result)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /paper/src/main/java/me/xneox/epicguard/paper/listener/PlayerQuitListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.paper.listener; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.handler.DisconnectHandler; 20 | import org.bukkit.event.EventHandler; 21 | import org.bukkit.event.Listener; 22 | import org.bukkit.event.player.PlayerQuitEvent; 23 | 24 | public class PlayerQuitListener extends DisconnectHandler implements Listener { 25 | public PlayerQuitListener(EpicGuard epicGuard) { 26 | super(epicGuard); 27 | } 28 | 29 | @EventHandler 30 | public void onQuit(PlayerQuitEvent event) { 31 | this.onDisconnect(event.getPlayer().getUniqueId()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /paper/src/main/java/me/xneox/epicguard/paper/listener/PlayerSettingsListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.paper.listener; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.handler.SettingsHandler; 20 | import org.bukkit.event.EventHandler; 21 | import org.bukkit.event.Listener; 22 | import org.bukkit.event.player.PlayerLocaleChangeEvent; 23 | 24 | public class PlayerSettingsListener extends SettingsHandler implements Listener { 25 | public PlayerSettingsListener(EpicGuard epicGuard) { 26 | super(epicGuard); 27 | } 28 | 29 | @EventHandler 30 | public void onSettingsChanged(PlayerLocaleChangeEvent event) { 31 | this.onSettingsChanged(event.getPlayer().getUniqueId()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /paper/src/main/java/me/xneox/epicguard/paper/listener/ServerPingListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.paper.listener; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.handler.PingHandler; 20 | import org.bukkit.event.EventHandler; 21 | import org.bukkit.event.EventPriority; 22 | import org.bukkit.event.Listener; 23 | import org.bukkit.event.server.ServerListPingEvent; 24 | 25 | public class ServerPingListener extends PingHandler implements Listener { 26 | public ServerPingListener(EpicGuard epicGuard) { 27 | super(epicGuard); 28 | } 29 | 30 | @EventHandler(priority = EventPriority.LOWEST) 31 | public void onPing(ServerListPingEvent event) { 32 | this.onPing(event.getAddress().getHostAddress()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /paper/src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: EpicGuard 2 | version: '${version}' 3 | main: me.xneox.epicguard.paper.EpicGuardPaper 4 | api-version: 1.16 5 | 6 | author: neox 7 | website: https://github.com/xxneox/EpicGuard 8 | description: Bot protection system for Minecraft servers. 9 | 10 | commands: 11 | epicguard: 12 | description: Main plugin command. 13 | permission: epicguard.admin 14 | aliases: [ guard, epicguardpaper, guardpaper ] -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "EpicGuard" 2 | 3 | dependencyResolutionManagement { 4 | repositories { 5 | maven("https://nexus.velocitypowered.com/repository/maven-public/") 6 | maven("https://papermc.io/repo/repository/maven-public/") 7 | maven("https://repo.aikar.co/content/groups/aikar/") 8 | mavenCentral() 9 | } 10 | } 11 | 12 | include("core", "paper", "velocity", "waterfall") -------------------------------------------------------------------------------- /velocity/build.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencies { 2 | implementation(project(":core")) 3 | 4 | // TODO: Download these on runtime. 5 | implementation("mysql:mysql-connector-java:8.0.27") 6 | implementation("org.xerial:sqlite-jdbc:3.36.0.3") 7 | 8 | compileOnly("com.velocitypowered:velocity-api:3.1.0") 9 | annotationProcessor("com.velocitypowered:velocity-api:3.1.0") 10 | } 11 | 12 | tasks { 13 | build { 14 | dependsOn(shadowJar) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /velocity/src/main/java/me/xneox/epicguard/velocity/EpicGuardVelocity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.velocity; 17 | 18 | import com.google.inject.Inject; 19 | import com.velocitypowered.api.event.Subscribe; 20 | import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; 21 | import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; 22 | import com.velocitypowered.api.plugin.Plugin; 23 | import com.velocitypowered.api.proxy.ProxyServer; 24 | import java.util.UUID; 25 | import java.util.concurrent.TimeUnit; 26 | import me.xneox.epicguard.core.EpicGuard; 27 | import me.xneox.epicguard.core.Platform; 28 | import me.xneox.epicguard.core.util.VersionUtils; 29 | import me.xneox.epicguard.velocity.listener.DisconnectListener; 30 | import me.xneox.epicguard.velocity.listener.PlayerSettingsListener; 31 | import me.xneox.epicguard.velocity.listener.PostLoginListener; 32 | import me.xneox.epicguard.velocity.listener.PreLoginListener; 33 | import me.xneox.epicguard.velocity.listener.ServerPingListener; 34 | import net.kyori.adventure.audience.Audience; 35 | import net.kyori.adventure.text.Component; 36 | import org.jetbrains.annotations.NotNull; 37 | import org.slf4j.Logger; 38 | 39 | @Plugin( 40 | id = "epicguard", 41 | name = "EpicGuard", 42 | version = VersionUtils.CURRENT_VERSION, 43 | description = "Bot protection system for Minecraft servers.", 44 | url = "https://github.com/xxneox/EpicGuard", 45 | authors = "neox") 46 | public class EpicGuardVelocity implements Platform { 47 | private final ProxyServer server; 48 | private final Logger logger; 49 | 50 | private EpicGuard epicGuard; 51 | 52 | @Inject 53 | public EpicGuardVelocity(ProxyServer server, Logger logger) { 54 | this.server = server; 55 | this.logger = logger; 56 | } 57 | 58 | @Subscribe 59 | public void onEnable(ProxyInitializeEvent e) { 60 | this.epicGuard = new EpicGuard(this); 61 | 62 | var commandManager = this.server.getCommandManager(); 63 | var meta = commandManager 64 | .metaBuilder("epicguard") 65 | .aliases("guard", "epicguardvelocity", "guardvelocity") 66 | .build(); 67 | 68 | commandManager.register(meta, new VelocityCommandHandler(this.epicGuard)); 69 | 70 | var eventManager = this.server.getEventManager(); 71 | eventManager.register(this, new PostLoginListener(this.epicGuard)); 72 | eventManager.register(this, new PreLoginListener(this.epicGuard)); 73 | eventManager.register(this, new DisconnectListener(this.epicGuard)); 74 | eventManager.register(this, new ServerPingListener(this.epicGuard)); 75 | eventManager.register(this, new PlayerSettingsListener(this.epicGuard)); 76 | } 77 | 78 | @Subscribe 79 | public void onDisable(ProxyShutdownEvent e) { 80 | this.epicGuard.shutdown(); 81 | } 82 | 83 | @Override 84 | public @NotNull String platformVersion() { 85 | return this.server.getVersion().toString(); 86 | } 87 | 88 | @Override 89 | public @NotNull Logger logger() { 90 | return this.logger; 91 | } 92 | 93 | @Override 94 | public Audience audience(@NotNull UUID uuid) { 95 | return this.server.getPlayer(uuid).orElse(null); 96 | } 97 | 98 | @Override 99 | public void disconnectUser(@NotNull UUID uuid, @NotNull Component message) { 100 | this.server.getPlayer(uuid).ifPresent(player -> player.disconnect(message)); 101 | } 102 | 103 | @Override 104 | public void runTaskLater(@NotNull Runnable task, long seconds) { 105 | this.server.getScheduler().buildTask(this, task).delay(seconds, TimeUnit.SECONDS).schedule(); 106 | } 107 | 108 | @Override 109 | public void scheduleRepeatingTask(@NotNull Runnable task, long seconds) { 110 | this.server.getScheduler().buildTask(this, task).repeat(seconds, TimeUnit.SECONDS).schedule(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /velocity/src/main/java/me/xneox/epicguard/velocity/VelocityCommandHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.velocity; 17 | 18 | import com.velocitypowered.api.command.SimpleCommand; 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import me.xneox.epicguard.core.EpicGuard; 22 | import me.xneox.epicguard.core.command.CommandHandler; 23 | 24 | public class VelocityCommandHandler extends CommandHandler implements SimpleCommand { 25 | public VelocityCommandHandler(EpicGuard epicGuard) { 26 | super(epicGuard); 27 | } 28 | 29 | @Override 30 | public void execute(Invocation invocation) { 31 | this.handleCommand(invocation.arguments(), invocation.source()); 32 | } 33 | 34 | @Override 35 | public List suggest(Invocation invocation) { 36 | return new ArrayList<>(this.handleSuggestions(invocation.arguments())); 37 | } 38 | 39 | @Override 40 | public boolean hasPermission(Invocation invocation) { 41 | return invocation.source().hasPermission("epicguard.admin"); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /velocity/src/main/java/me/xneox/epicguard/velocity/listener/DisconnectListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.velocity.listener; 17 | 18 | import com.velocitypowered.api.event.Subscribe; 19 | import com.velocitypowered.api.event.connection.DisconnectEvent; 20 | import me.xneox.epicguard.core.EpicGuard; 21 | import me.xneox.epicguard.core.handler.DisconnectHandler; 22 | 23 | public class DisconnectListener extends DisconnectHandler { 24 | public DisconnectListener(EpicGuard epicGuard) { 25 | super(epicGuard); 26 | } 27 | 28 | @Subscribe 29 | public void onDisconnect(DisconnectEvent event) { 30 | var player = event.getPlayer(); 31 | this.onDisconnect(player.getUniqueId()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /velocity/src/main/java/me/xneox/epicguard/velocity/listener/PlayerSettingsListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.velocity.listener; 17 | 18 | import com.velocitypowered.api.event.Subscribe; 19 | import com.velocitypowered.api.event.player.PlayerSettingsChangedEvent; 20 | import me.xneox.epicguard.core.EpicGuard; 21 | import me.xneox.epicguard.core.handler.SettingsHandler; 22 | 23 | public class PlayerSettingsListener extends SettingsHandler { 24 | public PlayerSettingsListener(EpicGuard epicGuard) { 25 | super(epicGuard); 26 | } 27 | 28 | @Subscribe 29 | public void onPostLogin(PlayerSettingsChangedEvent event) { 30 | this.onSettingsChanged(event.getPlayer().getUniqueId()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /velocity/src/main/java/me/xneox/epicguard/velocity/listener/PostLoginListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.velocity.listener; 17 | 18 | import com.velocitypowered.api.event.Subscribe; 19 | import com.velocitypowered.api.event.connection.PostLoginEvent; 20 | import me.xneox.epicguard.core.EpicGuard; 21 | import me.xneox.epicguard.core.handler.PostLoginHandler; 22 | 23 | public class PostLoginListener extends PostLoginHandler { 24 | public PostLoginListener(EpicGuard epicGuard) { 25 | super(epicGuard); 26 | } 27 | 28 | @Subscribe 29 | public void onPostLogin(PostLoginEvent event) { 30 | var player = event.getPlayer(); 31 | this.onPostLogin(player.getUniqueId(), player.getRemoteAddress().getAddress().getHostAddress()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /velocity/src/main/java/me/xneox/epicguard/velocity/listener/PreLoginListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.velocity.listener; 17 | 18 | import com.velocitypowered.api.event.EventTask; 19 | import com.velocitypowered.api.event.PostOrder; 20 | import com.velocitypowered.api.event.Subscribe; 21 | import com.velocitypowered.api.event.connection.PreLoginEvent; 22 | import me.xneox.epicguard.core.EpicGuard; 23 | import me.xneox.epicguard.core.handler.PreLoginHandler; 24 | 25 | public class PreLoginListener extends PreLoginHandler { 26 | public PreLoginListener(EpicGuard epicGuard) { 27 | super(epicGuard); 28 | } 29 | 30 | @Subscribe(order = PostOrder.FIRST) 31 | public EventTask onPreLogin(PreLoginEvent event) { 32 | String address = event.getConnection().getRemoteAddress().getAddress().getHostAddress(); 33 | String nickname = event.getUsername(); 34 | 35 | return EventTask.async(() -> 36 | this.onPreLogin(address, nickname).ifPresent(result -> event.setResult(PreLoginEvent.PreLoginComponentResult.denied(result)))); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /velocity/src/main/java/me/xneox/epicguard/velocity/listener/ServerPingListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.velocity.listener; 17 | 18 | import com.velocitypowered.api.event.PostOrder; 19 | import com.velocitypowered.api.event.Subscribe; 20 | import com.velocitypowered.api.event.proxy.ProxyPingEvent; 21 | import me.xneox.epicguard.core.EpicGuard; 22 | import me.xneox.epicguard.core.handler.PingHandler; 23 | 24 | public class ServerPingListener extends PingHandler { 25 | public ServerPingListener(EpicGuard epicGuard) { 26 | super(epicGuard); 27 | } 28 | 29 | @Subscribe(order = PostOrder.FIRST) 30 | public void onPing(ProxyPingEvent event) { 31 | this.onPing(event.getConnection().getRemoteAddress().getAddress().getHostAddress()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /waterfall/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar 2 | 3 | dependencies { 4 | implementation(project(":core")) 5 | 6 | implementation("net.kyori:adventure-platform-bungeecord:4.0.1") 7 | compileOnly("io.github.waterfallmc:waterfall-api:1.17-R0.1-SNAPSHOT") 8 | } 9 | 10 | tasks.withType { 11 | relocate("net.kyori.adventure", "me.xneox.epicguard.waterfall.adventure") 12 | relocate("net.kyori.examination", "me.xneox.epicguard.waterfall.examination") 13 | } 14 | 15 | tasks { 16 | build { 17 | dependsOn(shadowJar) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /waterfall/src/main/java/me/xneox/epicguard/waterfall/BungeeCommandHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.waterfall; 17 | 18 | import me.xneox.epicguard.core.command.CommandHandler; 19 | import net.md_5.bungee.api.CommandSender; 20 | import net.md_5.bungee.api.plugin.Command; 21 | import net.md_5.bungee.api.plugin.TabExecutor; 22 | 23 | // why bungee... why Command is an abstract class? 24 | public class BungeeCommandHandler extends Command implements TabExecutor { 25 | private final CommandHandler commandHandler; 26 | private final EpicGuardWaterfall plugin; 27 | 28 | public BungeeCommandHandler(EpicGuardWaterfall plugin) { 29 | super("epicguard", "epicguard.admin", "guard", "epicguardbungee", "guardbungee"); 30 | this.plugin = plugin; 31 | this.commandHandler = new CommandHandler(plugin.epicGuard()); 32 | } 33 | 34 | @Override 35 | public void execute(CommandSender sender, String[] args) { 36 | this.commandHandler.handleCommand(args, this.plugin.adventure().sender(sender)); 37 | } 38 | 39 | @Override 40 | public Iterable onTabComplete(CommandSender sender, String[] args) { 41 | return this.commandHandler.handleSuggestions(args); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /waterfall/src/main/java/me/xneox/epicguard/waterfall/BungeeUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.waterfall; 17 | 18 | import net.kyori.adventure.text.Component; 19 | import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; 20 | import net.md_5.bungee.api.chat.BaseComponent; 21 | 22 | public final class BungeeUtils { 23 | /** 24 | * Converts an Adventure component to a bungeecord's component. 25 | */ 26 | public static BaseComponent[] toLegacyComponent(Component component) { 27 | return BungeeComponentSerializer.get().serialize(component); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /waterfall/src/main/java/me/xneox/epicguard/waterfall/EpicGuardWaterfall.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.waterfall; 17 | 18 | import java.util.UUID; 19 | import java.util.concurrent.TimeUnit; 20 | import me.xneox.epicguard.core.EpicGuard; 21 | import me.xneox.epicguard.core.Platform; 22 | import me.xneox.epicguard.waterfall.listener.DisconnectListener; 23 | import me.xneox.epicguard.waterfall.listener.PlayerSettingsListener; 24 | import me.xneox.epicguard.waterfall.listener.PostLoginListener; 25 | import me.xneox.epicguard.waterfall.listener.PreLoginListener; 26 | import me.xneox.epicguard.waterfall.listener.ServerPingListener; 27 | import net.kyori.adventure.audience.Audience; 28 | import net.kyori.adventure.platform.bungeecord.BungeeAudiences; 29 | import net.kyori.adventure.text.Component; 30 | import net.md_5.bungee.api.ProxyServer; 31 | import net.md_5.bungee.api.plugin.Plugin; 32 | import org.jetbrains.annotations.NotNull; 33 | import org.slf4j.Logger; 34 | 35 | public class EpicGuardWaterfall extends Plugin implements Platform { 36 | private EpicGuard epicGuard; 37 | private BungeeAudiences adventure; 38 | 39 | @Override 40 | public void onEnable() { 41 | this.epicGuard = new EpicGuard(this); 42 | this.adventure = BungeeAudiences.create(this); 43 | 44 | var pluginManager = this.getProxy().getPluginManager(); 45 | pluginManager.registerListener(this, new PreLoginListener(this.epicGuard)); 46 | pluginManager.registerListener(this, new DisconnectListener(this.epicGuard)); 47 | pluginManager.registerListener(this, new PostLoginListener(this.epicGuard)); 48 | pluginManager.registerListener(this, new ServerPingListener(this.epicGuard)); 49 | pluginManager.registerListener(this, new PlayerSettingsListener(this.epicGuard)); 50 | 51 | pluginManager.registerCommand(this, new BungeeCommandHandler(this)); 52 | } 53 | 54 | @Override 55 | public void onDisable() { 56 | this.epicGuard.shutdown(); 57 | } 58 | 59 | @Override 60 | public @NotNull String platformVersion() { 61 | return ProxyServer.getInstance().getName() + "-" + ProxyServer.getInstance().getVersion(); 62 | } 63 | 64 | @Override 65 | public @NotNull Logger logger() { 66 | return this.getSLF4JLogger(); 67 | } 68 | 69 | @Override 70 | public Audience audience(@NotNull UUID uuid) { 71 | var player = ProxyServer.getInstance().getPlayer(uuid); 72 | if (player != null) { 73 | return this.adventure.player(player); 74 | } 75 | return null; 76 | } 77 | 78 | @Override 79 | public void disconnectUser(@NotNull UUID uuid, @NotNull Component component) { 80 | ProxyServer.getInstance() 81 | .getPlayer(uuid) 82 | .disconnect(BungeeUtils.toLegacyComponent(component)); 83 | } 84 | 85 | @Override 86 | public void runTaskLater(@NotNull Runnable task, long seconds) { 87 | this.getProxy().getScheduler().schedule(this, task, seconds, TimeUnit.SECONDS); 88 | } 89 | 90 | @Override 91 | public void scheduleRepeatingTask(@NotNull Runnable task, long seconds) { 92 | this.getProxy().getScheduler().schedule(this, task, seconds, seconds, TimeUnit.SECONDS); 93 | } 94 | 95 | @NotNull 96 | public BungeeAudiences adventure() { 97 | return this.adventure; 98 | } 99 | 100 | @NotNull 101 | public EpicGuard epicGuard() { 102 | return this.epicGuard; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /waterfall/src/main/java/me/xneox/epicguard/waterfall/listener/DisconnectListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.waterfall.listener; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.handler.DisconnectHandler; 20 | import net.md_5.bungee.api.event.PlayerDisconnectEvent; 21 | import net.md_5.bungee.api.plugin.Listener; 22 | import net.md_5.bungee.event.EventHandler; 23 | 24 | public class DisconnectListener extends DisconnectHandler implements Listener { 25 | public DisconnectListener(EpicGuard epicGuard) { 26 | super(epicGuard); 27 | } 28 | 29 | @EventHandler 30 | public void onPostLogin(PlayerDisconnectEvent event) { 31 | this.onDisconnect(event.getPlayer().getUniqueId()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /waterfall/src/main/java/me/xneox/epicguard/waterfall/listener/PlayerSettingsListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.waterfall.listener; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.handler.SettingsHandler; 20 | import net.md_5.bungee.api.event.SettingsChangedEvent; 21 | import net.md_5.bungee.api.plugin.Listener; 22 | import net.md_5.bungee.event.EventHandler; 23 | 24 | public class PlayerSettingsListener extends SettingsHandler implements Listener { 25 | public PlayerSettingsListener(EpicGuard epicGuard) { 26 | super(epicGuard); 27 | } 28 | 29 | @EventHandler 30 | public void onSettingsChanged(SettingsChangedEvent event) { 31 | this.onSettingsChanged(event.getPlayer().getUniqueId()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /waterfall/src/main/java/me/xneox/epicguard/waterfall/listener/PostLoginListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.waterfall.listener; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.handler.PostLoginHandler; 20 | import net.md_5.bungee.api.connection.ProxiedPlayer; 21 | import net.md_5.bungee.api.event.PostLoginEvent; 22 | import net.md_5.bungee.api.plugin.Listener; 23 | import net.md_5.bungee.event.EventHandler; 24 | 25 | public class PostLoginListener extends PostLoginHandler implements Listener { 26 | public PostLoginListener(EpicGuard epicGuard) { 27 | super(epicGuard); 28 | } 29 | 30 | @EventHandler 31 | public void onPostLogin(PostLoginEvent event) { 32 | ProxiedPlayer player = event.getPlayer(); 33 | 34 | //noinspection deprecation 35 | this.onPostLogin(player.getUniqueId(), player.getAddress().getAddress().getHostAddress()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /waterfall/src/main/java/me/xneox/epicguard/waterfall/listener/PreLoginListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.waterfall.listener; 17 | 18 | import me.xneox.epicguard.waterfall.BungeeUtils; 19 | import me.xneox.epicguard.core.EpicGuard; 20 | import me.xneox.epicguard.core.handler.PreLoginHandler; 21 | import net.md_5.bungee.api.event.PreLoginEvent; 22 | import net.md_5.bungee.api.plugin.Listener; 23 | import net.md_5.bungee.event.EventHandler; 24 | 25 | public class PreLoginListener extends PreLoginHandler implements Listener { 26 | public PreLoginListener(EpicGuard epicGuard) { 27 | super(epicGuard); 28 | } 29 | 30 | @EventHandler(priority = Byte.MIN_VALUE) 31 | public void onPreLogin(PreLoginEvent event) { 32 | //noinspection deprecation 33 | String address = event.getConnection().getAddress().getAddress().getHostAddress(); 34 | String nickname = event.getConnection().getName(); 35 | 36 | this.onPreLogin(address, nickname).ifPresent(result -> { 37 | event.setCancelled(true); 38 | event.setCancelReason(BungeeUtils.toLegacyComponent(result)); 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /waterfall/src/main/java/me/xneox/epicguard/waterfall/listener/ServerPingListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * EpicGuard is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * EpicGuard is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see 14 | */ 15 | 16 | package me.xneox.epicguard.waterfall.listener; 17 | 18 | import me.xneox.epicguard.core.EpicGuard; 19 | import me.xneox.epicguard.core.handler.PingHandler; 20 | import net.md_5.bungee.api.event.ProxyPingEvent; 21 | import net.md_5.bungee.api.plugin.Listener; 22 | import net.md_5.bungee.event.EventHandler; 23 | 24 | public class ServerPingListener extends PingHandler implements Listener { 25 | public ServerPingListener(EpicGuard epicGuard) { 26 | super(epicGuard); 27 | } 28 | 29 | @EventHandler(priority = Byte.MIN_VALUE) 30 | public void onPing(ProxyPingEvent event) { 31 | //noinspection deprecation 32 | this.onPing(event.getConnection().getAddress().getAddress().getHostAddress()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /waterfall/src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: EpicGuard 2 | version: ${version} 3 | main: me.xneox.epicguard.waterfall.EpicGuardWaterfall 4 | 5 | author: neox 6 | website: https://github.com/xxneox/EpicGuard 7 | description: Bot protection system for Minecraft servers. 8 | 9 | libraries: 10 | - org.xerial:sqlite-jdbc:3.36.0.3 --------------------------------------------------------------------------------