diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a5fb06012..d1b22996f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -25,8 +25,3 @@ updates: # Plugin require special evaluation about their compatibility - "com.lenis0012.bukkit:loginsecurity" - "com.comphenix.protocol:ProtocolLib" - - ignore: - # HikariCP dropped Java 8 support with 5.0 - - dependency-name: "com.zaxxer:HikariCP" - update-types: ["version-update:semver-major"] diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 93e5b9aa8..f91066207 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -25,7 +25,7 @@ jobs: if: ${{ github.event.workflow_run.conclusion == 'success' }} permissions: - # Only allow write for security, then all others default to read only + # Only allow 'write' permission for security, then all others default to read only security-events: write strategy: diff --git a/CHANGELOG.md b/CHANGELOG.md index af685534e..6dbef7513 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,29 @@ +# 2.0 + +## Major changes + +* Bumped minimum Java version to 11 make use of modern Java performance features + * Report back if really still need the old versions + * Then we could make use of versioned code, but that requires more coding effort + +## Added + +* Support for HTTP/2 for contacting Mojang + +## Changed + +* Updated many dependencies + +## Removed + +Dropped some features listed below. Please contact us if you still need them + +* Dropped Java support < 11 +* Removed configuration option to add multiple outgoing IPv4 towards Mojang +* Dropped support for ProtocolSupport seems to unsupported + +[...] A lot of changes + ### 1.11 * TODO: Replace reflection with methodhandles diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java index 8194e4e13..72b4b72f2 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java @@ -26,7 +26,7 @@ package com.github.games647.fastlogin.bukkit; import com.github.games647.craftapi.model.skin.SkinProperty; -import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey; +import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey; import com.github.games647.fastlogin.core.shared.LoginSession; import com.github.games647.fastlogin.core.storage.StoredProfile; import org.jetbrains.annotations.Nullable; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java index 2f58615d2..7d31a37cf 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java @@ -25,23 +25,21 @@ */ package com.github.games647.fastlogin.bukkit; -import com.comphenix.protocol.ProtocolLibrary; +import com.github.games647.fastlogin.bukkit.auth.AuthenticationBackend; +import com.github.games647.fastlogin.bukkit.auth.ConnectionListener; +import com.github.games647.fastlogin.bukkit.auth.protocollib.ProtocolAuthentication; +import com.github.games647.fastlogin.bukkit.auth.proxy.ProxyAuthentication; import com.github.games647.fastlogin.bukkit.command.CrackedCommand; import com.github.games647.fastlogin.bukkit.command.PremiumCommand; -import com.github.games647.fastlogin.bukkit.listener.ConnectionListener; -import com.github.games647.fastlogin.bukkit.listener.PaperCacheListener; -import com.github.games647.fastlogin.bukkit.listener.protocollib.ProtocolLibListener; -import com.github.games647.fastlogin.bukkit.listener.protocollib.SkinApplyListener; -import com.github.games647.fastlogin.bukkit.listener.protocolsupport.ProtocolSupportListener; -import com.github.games647.fastlogin.bukkit.task.DelayedAuthHook; +import com.github.games647.fastlogin.bukkit.hook.DelayedAuthHook; import com.github.games647.fastlogin.core.CommonUtil; import com.github.games647.fastlogin.core.PremiumStatus; -import com.github.games647.fastlogin.core.antibot.AntiBotService; import com.github.games647.fastlogin.core.hooks.bedrock.BedrockService; import com.github.games647.fastlogin.core.hooks.bedrock.FloodgateService; import com.github.games647.fastlogin.core.hooks.bedrock.GeyserService; import com.github.games647.fastlogin.core.shared.FastLoginCore; import com.github.games647.fastlogin.core.shared.PlatformPlugin; +import lombok.Getter; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -55,6 +53,8 @@ import java.net.InetSocketAddress; import java.nio.file.Path; import java.time.Duration; +import java.util.Collection; +import java.util.HashSet; import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -71,18 +71,30 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin premiumPlayers = new ConcurrentHashMap<>(); private final Logger logger; - private boolean serverStarted; - private BungeeManager bungeeManager; private final BukkitScheduler scheduler; + + @Getter + private final Collection pendingConfirms = new HashSet<>(); + + @Getter private FastLoginCore core; + + @Getter private FloodgateService floodgateService; private GeyserService geyserService; private PremiumPlaceholder premiumPlaceholder; + @Getter + private AuthenticationBackend backend; + + @Getter + private boolean initialized; + public FastLoginBukkit() { this.logger = CommonUtil.initializeLoggerService(getLogger()); this.scheduler = new BukkitScheduler(this, logger); @@ -104,51 +116,42 @@ public void onEnable() { setEnabled(false); } - bungeeManager = new BungeeManager(this); - bungeeManager.initialize(); - - PluginManager pluginManager = getServer().getPluginManager(); - if (bungeeManager.isEnabled()) { - markInitialized(); - } else { - if (!core.setupDatabase()) { - setEnabled(false); - return; - } - - AntiBotService antiBotService = core.getAntiBotService(); - if (pluginManager.isPluginEnabled("ProtocolSupport")) { - pluginManager.registerEvents(new ProtocolSupportListener(this, antiBotService), this); - } else if (pluginManager.isPluginEnabled("ProtocolLib")) { - ProtocolLibListener.register(this, antiBotService, core.getConfig().getBoolean("verifyClientKeys")); - - //if server is using paper - we need to set the skin at pre login anyway, so no need for this listener - if (!isPaper() && getConfig().getBoolean("forwardSkin")) { - pluginManager.registerEvents(new SkinApplyListener(this), this); - } - } else { - logger.warn("Either ProtocolLib or ProtocolSupport have to be installed if you don't use BungeeCord"); - setEnabled(false); - return; - } + backend = initializeAuthenticationBackend(); + if (backend == null) { + logger.warn("Either ProtocolLib or ProtocolSupport have to be installed if you don't use BungeeCord"); + setEnabled(false); + return; } - //delay dependency setup because we load the plugin very early where plugins are initialized yet - getServer().getScheduler().runTaskLater(this, new DelayedAuthHook(this), 5L); + backend.init(getServer().getPluginManager()); + PluginManager pluginManager = getServer().getPluginManager(); pluginManager.registerEvents(new ConnectionListener(this), this); - //if server is using paper - we need to add one more listener to correct the user cache usage - if (isPaper()) { - pluginManager.registerEvents(new PaperCacheListener(this), this); - } - registerCommands(); if (pluginManager.isPluginEnabled("PlaceholderAPI")) { premiumPlaceholder = new PremiumPlaceholder(this); premiumPlaceholder.register(); } + + // delay dependency setup because we load the plugin very early where plugins are initialized yet + getServer().getScheduler().runTaskLater(this, new DelayedAuthHook(this), 5L); + } + + private AuthenticationBackend initializeAuthenticationBackend() { + AuthenticationBackend proxyVerifier = new ProxyAuthentication(this); + if (proxyVerifier.isAvailable()) { + return proxyVerifier; + } + + logger.warn("Disabling Minecraft proxy configuration. Assuming direct connections from now on."); + AuthenticationBackend protocolAuthentication = new ProtocolAuthentication(this); + if (protocolAuthentication.isAvailable()) { + return protocolAuthentication; + } + + return null; } private void registerCommands() { @@ -182,27 +185,15 @@ public void onDisable() { core.close(); } - if (bungeeManager != null) { - bungeeManager.cleanup(); + if (backend != null) { + backend.stop(); } if (premiumPlaceholder != null && getServer().getPluginManager().isPluginEnabled("PlaceholderAPI")) { - try { - premiumPlaceholder.unregister(); - } catch (Exception | NoSuchMethodError exception) { - logger.error("Failed to unregister placeholder", exception); - } - } - - if (getServer().getPluginManager().isPluginEnabled("ProtocolLib")) { - ProtocolLibrary.getProtocolManager().getAsynchronousManager().unregisterAsyncHandlers(this); + premiumPlaceholder.unregister(); } } - public FastLoginCore getCore() { - return core; - } - /** * Gets a thread-safe map about players which are connecting to the server are being checked to be premium (paid * account) @@ -232,10 +223,6 @@ public void removeSession(InetSocketAddress address) { loginSession.remove(id); } - public Map getPremiumPlayers() { - return premiumPlayers; - } - /** * Fetches the premium status of an online player. * {@snippet : @@ -263,24 +250,6 @@ public Map getPremiumPlayers() { return premiumPlayers.getOrDefault(onlinePlayer, PremiumStatus.UNKNOWN); } - /** - * Wait before the server is fully started. This is workaround, because connections right on startup are not - * injected by ProtocolLib - * - * @return true if ProtocolLib can now intercept packets - */ - public boolean isServerFullyStarted() { - return serverStarted; - } - - public void markInitialized() { - this.serverStarted = true; - } - - public BungeeManager getBungeeManager() { - return bungeeManager; - } - @Override public Path getPluginFolder() { return getDataFolder().toPath(); @@ -313,12 +282,21 @@ public boolean isPluginInstalled(String name) { return Bukkit.getServer().getPluginManager().getPlugin(name) != null; } - public FloodgateService getFloodgateService() { - return floodgateService; + public void setInitialized(boolean hookFound) { + if (backend instanceof ProxyAuthentication) { + logger.info("BungeeCord setting detected. No auth plugin is required"); + } else if (!hookFound) { + logger.warn("No auth plugin were found by this plugin " + + "(other plugins could hook into this after the initialization of this plugin)" + + "and BungeeCord is deactivated. " + + "Either one or both of the checks have to pass in order to use this plugin"); + } + + initialized = true; } - public GeyserService getGeyserService() { - return geyserService; + public ProxyAuthentication getBungeeManager() { + return (ProxyAuthentication) backend; } @Override @@ -326,19 +304,7 @@ public BedrockService getBedrockService() { if (floodgateService != null) { return floodgateService; } - return geyserService; - } - - private boolean isPaper() { - return isClassAvailable("com.destroystokyo.paper.PaperConfig").isPresent() - || isClassAvailable("io.papermc.paper.configuration.Configuration").isPresent(); - } - private Optional> isClassAvailable(String clazzName) { - try { - return Optional.of(Class.forName(clazzName)); - } catch (ClassNotFoundException e) { - return Optional.empty(); - } + return geyserService; } } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolLoginSource.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/AuthenticationBackend.java similarity index 52% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolLoginSource.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/AuthenticationBackend.java index d7f8b4947..63ed92cb8 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolLoginSource.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/AuthenticationBackend.java @@ -23,44 +23,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener.protocolsupport; +package com.github.games647.fastlogin.bukkit.auth; -import com.github.games647.fastlogin.core.shared.LoginSource; -import protocolsupport.api.events.PlayerLoginStartEvent; +import org.bukkit.plugin.PluginManager; -import java.net.InetSocketAddress; +public interface AuthenticationBackend { -public class ProtocolLoginSource implements LoginSource { + boolean isAvailable(); - private final PlayerLoginStartEvent loginStartEvent; + void init(PluginManager pluginManager); - public ProtocolLoginSource(PlayerLoginStartEvent loginStartEvent) { - this.loginStartEvent = loginStartEvent; - } - - @Override - public void enableOnlinemode() { - loginStartEvent.setOnlineMode(true); - } - - @Override - public void kick(String message) { - loginStartEvent.denyLogin(message); - } - - @Override - public InetSocketAddress getAddress() { - return loginStartEvent.getConnection().getRawAddress(); - } - - public PlayerLoginStartEvent getLoginStartEvent() { - return loginStartEvent; - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + '{' - + "loginStartEvent=" + loginStartEvent - + '}'; - } + void stop(); } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ConnectionListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/ConnectionListener.java similarity index 80% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ConnectionListener.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/ConnectionListener.java index 2bacbc5d8..6f09c9823 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ConnectionListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/ConnectionListener.java @@ -23,23 +23,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener; +package com.github.games647.fastlogin.bukkit.auth; import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.bukkit.task.FloodgateAuthTask; -import com.github.games647.fastlogin.bukkit.task.ForceLoginTask; import com.github.games647.fastlogin.core.hooks.bedrock.FloodgateService; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerLoginEvent; -import org.bukkit.event.player.PlayerLoginEvent.Result; import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.metadata.Metadatable; import org.geysermc.floodgate.api.player.FloodgatePlayer; /** @@ -56,14 +50,6 @@ public ConnectionListener(FastLoginBukkit plugin) { this.plugin = plugin; } - @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerLogin(PlayerLoginEvent loginEvent) { - removeBlockedStatus(loginEvent.getPlayer()); - if (loginEvent.getResult() == Result.ALLOWED && !plugin.isServerFullyStarted()) { - loginEvent.disallow(Result.KICK_OTHER, plugin.getCore().getMessage("not-started")); - } - } - @EventHandler(ignoreCancelled = true) public void onPlayerJoin(PlayerJoinEvent joinEvent) { Player player = joinEvent.getPlayer(); @@ -102,21 +88,13 @@ private void delayForceLogin(Player player) { Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session); Bukkit.getScheduler().runTaskAsynchronously(plugin, forceLoginTask); } - - plugin.getBungeeManager().markJoinEventFired(player); } @EventHandler public void onPlayerQuit(PlayerQuitEvent quitEvent) { Player player = quitEvent.getPlayer(); - removeBlockedStatus(player); - plugin.getCore().getPendingConfirms().remove(player.getUniqueId()); + plugin.getPendingConfirms().remove(player.getUniqueId()); plugin.getPremiumPlayers().remove(player.getUniqueId()); - plugin.getBungeeManager().cleanup(player); - } - - private void removeBlockedStatus(Metadatable player) { - player.removeMetadata(plugin.getName(), plugin); } } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/task/FloodgateAuthTask.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/FloodgateAuthTask.java similarity index 98% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/task/FloodgateAuthTask.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/FloodgateAuthTask.java index 64d2977a1..d11ac2ea6 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/task/FloodgateAuthTask.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/FloodgateAuthTask.java @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.task; +package com.github.games647.fastlogin.bukkit.auth; import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/task/ForceLoginTask.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/ForceLoginTask.java similarity index 97% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/task/ForceLoginTask.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/ForceLoginTask.java index e5daaf55a..03f8aabd4 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/task/ForceLoginTask.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/ForceLoginTask.java @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.task; +package com.github.games647.fastlogin.bukkit.auth; import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; @@ -80,7 +80,7 @@ public FastLoginAutoLoginEvent callFastLoginAutoLoginEvent(LoginSession session, @Override public void onForceActionSuccess(LoginSession session) { - if (core.getPlugin().getBungeeManager().isEnabled()) { + if (core.getPlugin().getBungeeManager().isAvailable()) { core.getPlugin().getBungeeManager().sendPluginMessage(player, new SuccessMessage()); } } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/InetUtils.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/InetUtils.java similarity index 98% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/InetUtils.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/InetUtils.java index 24cf053cc..3d3bdf9f0 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/InetUtils.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/InetUtils.java @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit; +package com.github.games647.fastlogin.bukkit.auth; import java.net.InetAddress; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/LocalAuthentication.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/LocalAuthentication.java new file mode 100644 index 000000000..7c8a46969 --- /dev/null +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/LocalAuthentication.java @@ -0,0 +1,70 @@ +/* + * SPDX-License-Identifier: MIT + * + * The MIT License (MIT) + * + * Copyright (c) 2015-2024 games647 and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.games647.fastlogin.bukkit.auth; + +import com.github.games647.fastlogin.bukkit.FastLoginBukkit; +import com.github.games647.fastlogin.bukkit.auth.protocollib.SkinApplyListener; +import org.bukkit.plugin.PluginManager; + +import java.util.Optional; + +public abstract class LocalAuthentication implements AuthenticationBackend { + + protected final FastLoginBukkit plugin; + + protected LocalAuthentication(FastLoginBukkit plugin) { + this.plugin = plugin; + } + + @Override + public void init(PluginManager pluginManager) { + if (!plugin.getCore().setupDatabase()) { + plugin.setEnabled(false); + return; + } + + // if server is using paper - we need to add one more listener to correct the user cache usage + if (isPaper()) { + pluginManager.registerEvents(new PaperCacheListener(plugin), plugin); + } else if (plugin.getConfig().getBoolean("forwardSkin")) { + //if server is using paper - we need to set the skin at pre login anyway, so no need for this listener + pluginManager.registerEvents(new SkinApplyListener(plugin), plugin); + } + } + + private boolean isPaper() { + return isClassAvailable("com.destroystokyo.paper.PaperConfig").isPresent() + || isClassAvailable("io.papermc.paper.configuration.Configuration").isPresent(); + } + + private Optional> isClassAvailable(String clazzName) { + try { + return Optional.of(Class.forName(clazzName)); + } catch (ClassNotFoundException e) { + return Optional.empty(); + } + } +} diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/PaperCacheListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/PaperCacheListener.java similarity index 98% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/PaperCacheListener.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/PaperCacheListener.java index acc9c1249..ceae9fdd8 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/PaperCacheListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/PaperCacheListener.java @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener; +package com.github.games647.fastlogin.bukkit.auth; import com.destroystokyo.paper.profile.ProfileProperty; import com.github.games647.craftapi.model.skin.Textures; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/EncryptionUtil.java similarity index 98% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/EncryptionUtil.java index 0f86a3e4b..c0d853c21 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/EncryptionUtil.java @@ -23,10 +23,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener.protocollib; +package com.github.games647.fastlogin.bukkit.auth.protocollib; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey; +import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey; import com.google.common.hash.Hasher; import com.google.common.hash.Hashing; import com.google.common.io.Resources; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/NameCheckTask.java similarity index 96% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/NameCheckTask.java index 05c23e62a..06d700e27 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/NameCheckTask.java @@ -23,14 +23,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener.protocollib; +package com.github.games647.fastlogin.bukkit.auth.protocollib; import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.events.PacketEvent; import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; +import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey; import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPreLoginEvent; -import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey; import com.github.games647.fastlogin.core.shared.JoinManagement; import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent; import com.github.games647.fastlogin.core.storage.StoredProfile; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/ProtocolAuthentication.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/ProtocolAuthentication.java new file mode 100644 index 000000000..768b33f4c --- /dev/null +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/ProtocolAuthentication.java @@ -0,0 +1,72 @@ +/* + * SPDX-License-Identifier: MIT + * + * The MIT License (MIT) + * + * Copyright (c) 2015-2024 games647 and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.games647.fastlogin.bukkit.auth.protocollib; + +import com.comphenix.protocol.ProtocolLibrary; +import com.github.games647.fastlogin.bukkit.FastLoginBukkit; +import com.github.games647.fastlogin.bukkit.auth.LocalAuthentication; +import com.github.games647.fastlogin.core.antibot.AntiBotService; +import com.github.games647.fastlogin.core.shared.FastLoginCore; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.plugin.PluginManager; + +public class ProtocolAuthentication extends LocalAuthentication implements Listener { + + public ProtocolAuthentication(FastLoginBukkit plugin) { + super(plugin); + } + + @Override + public boolean isAvailable() { + return plugin.getServer().getPluginManager().isPluginEnabled("ProtocolLib"); + } + + @Override + public void init(PluginManager pluginManager) { + pluginManager.registerEvents(this, plugin); + + FastLoginCore core = plugin.getCore(); + AntiBotService antiBotService = core.getAntiBotService(); + ProtocolLibListener.register(plugin, antiBotService, core.getConfig().getBoolean("verifyClientKeys")); + } + + @Override + public void stop() { + ProtocolLibrary.getProtocolManager().getAsynchronousManager().unregisterAsyncHandlers(plugin); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerLogin(PlayerLoginEvent loginEvent) { + if (loginEvent.getResult() == PlayerLoginEvent.Result.ALLOWED && !plugin.isInitialized()) { + loginEvent.disallow(PlayerLoginEvent.Result.KICK_OTHER, plugin.getCore().getMessage("not-started")); + } + } +} diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/ProtocolLibListener.java similarity index 98% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/ProtocolLibListener.java index 2f8610483..071f2c1ca 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/ProtocolLibListener.java @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener.protocollib; +package com.github.games647.fastlogin.bukkit.auth.protocollib; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; @@ -42,7 +42,7 @@ import com.comphenix.protocol.wrappers.WrappedGameProfile; import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey; +import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey; import com.github.games647.fastlogin.core.antibot.AntiBotService; import com.github.games647.fastlogin.core.antibot.AntiBotService.Action; import com.mojang.datafixers.util.Either; @@ -110,7 +110,7 @@ public static void register(FastLoginBukkit plugin, AntiBotService antiBotServic public void onPacketReceiving(PacketEvent packetEvent) { if (packetEvent.isCancelled() || plugin.getCore().getAuthPluginHook() == null - || !plugin.isServerFullyStarted()) { + || !plugin.isInitialized()) { return; } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/ProtocolLibLoginSource.java similarity index 96% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/ProtocolLibLoginSource.java index f32f3fa43..258d2300f 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/ProtocolLibLoginSource.java @@ -23,14 +23,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener.protocollib; +package com.github.games647.fastlogin.bukkit.auth.protocollib; import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.ProtocolManager; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.wrappers.WrappedChatComponent; -import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey; +import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey; import com.github.games647.fastlogin.core.shared.LoginSource; import org.bukkit.entity.Player; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SkinApplyListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/SkinApplyListener.java similarity index 97% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SkinApplyListener.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/SkinApplyListener.java index f3960672c..49f906f84 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SkinApplyListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/SkinApplyListener.java @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener.protocollib; +package com.github.games647.fastlogin.bukkit.auth.protocollib; import com.comphenix.protocol.wrappers.WrappedGameProfile; import com.comphenix.protocol.wrappers.WrappedSignedProperty; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/VerifyResponseTask.java similarity index 98% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/VerifyResponseTask.java index 55f3b9609..46647c2ab 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/VerifyResponseTask.java @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener.protocollib; +package com.github.games647.fastlogin.bukkit.auth.protocollib; import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.events.PacketContainer; @@ -47,8 +47,8 @@ import com.github.games647.craftapi.resolver.MojangResolver; import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.bukkit.InetUtils; -import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey; +import com.github.games647.fastlogin.bukkit.auth.InetUtils; +import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey; import lombok.val; import org.bukkit.entity.Player; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/packet/ClientPublicKey.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/packet/ClientPublicKey.java similarity index 96% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/packet/ClientPublicKey.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/packet/ClientPublicKey.java index 1ea95d424..7e2591497 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/packet/ClientPublicKey.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/protocollib/packet/ClientPublicKey.java @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener.protocollib.packet; +package com.github.games647.fastlogin.bukkit.auth.protocollib.packet; import lombok.Value; import lombok.experimental.Accessors; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BungeeManager.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/proxy/ProxyAuthentication.java similarity index 55% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BungeeManager.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/proxy/ProxyAuthentication.java index c1a462759..b426c7410 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BungeeManager.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/proxy/ProxyAuthentication.java @@ -23,9 +23,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit; +package com.github.games647.fastlogin.bukkit.auth.proxy; -import com.github.games647.fastlogin.bukkit.listener.BungeeListener; +import com.github.games647.fastlogin.bukkit.FastLoginBukkit; +import com.github.games647.fastlogin.bukkit.auth.AuthenticationBackend; import com.github.games647.fastlogin.core.message.ChannelMessage; import com.github.games647.fastlogin.core.message.LoginActionMessage; import com.github.games647.fastlogin.core.message.NamespaceKey; @@ -33,103 +34,63 @@ import com.google.common.io.ByteStreams; import org.bukkit.Bukkit; import org.bukkit.Server; -import org.bukkit.entity.Player; +import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.messaging.PluginMessageRecipient; -import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Stream; import static com.github.games647.fastlogin.core.message.ChangePremiumMessage.CHANGE_CHANNEL; import static com.github.games647.fastlogin.core.message.SuccessMessage.SUCCESS_CHANNEL; -import static java.util.stream.Collectors.toSet; -public class BungeeManager { - - private static final String LEGACY_FILE_NAME = "proxy-whitelist.txt"; - private static final String FILE_NAME = "allowed-proxies.txt"; - - //null if proxies allowed list is empty so bungeecord support is disabled - private Set proxyIds; +public class ProxyAuthentication implements AuthenticationBackend { private final FastLoginBukkit plugin; - private boolean enabled; - - private final Collection firedJoinEvents = new HashSet<>(); + private ProxyVerifier verifier; - public BungeeManager(FastLoginBukkit plugin) { + public ProxyAuthentication(FastLoginBukkit plugin) { this.plugin = plugin; } - public void cleanup() { - //remove old blocked status - Bukkit.getOnlinePlayers().forEach(player -> player.removeMetadata(plugin.getName(), plugin)); - } - public void sendPluginMessage(PluginMessageRecipient player, ChannelMessage message) { - if (player != null) { - ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput(); - message.writeTo(dataOutput); - - NamespaceKey channel = new NamespaceKey(plugin.getName(), message.getChannelName()); - player.sendPluginMessage(plugin, channel.getCombinedName(), dataOutput.toByteArray()); - } + @Override + public boolean isAvailable() { + return detectProxy(); } - public boolean isEnabled() { - return enabled; - } + @Override + public void init(PluginManager pluginManager) { + verifier = new ProxyVerifier(plugin); + verifier.loadSecrets(); - public void initialize() { - enabled = detectProxy(); + registerPluginChannels(); - if (enabled) { - proxyIds = loadBungeeCordIds(); - if (proxyIds.isEmpty()) { - plugin.getLog().info("No valid IDs found. Minecraft proxy support cannot work in the current state"); - } + pluginManager.registerEvents(new ProxyConnectionListener(plugin, verifier), plugin); - registerPluginChannels(); - plugin.getLog().info("Found enabled proxy configuration"); - plugin.getLog().info("Remember to follow the proxy guide to complete your setup"); - } else { - plugin.getLog().warn("Disabling Minecraft proxy configuration. Assuming direct connections from now on."); - } + plugin.getLog().info("Found enabled proxy configuration"); + plugin.getLog().info("Remember to follow the proxy guide to complete your setup"); } - private boolean isProxySupported(String className, String fieldName) - throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { - return Class.forName(className).getDeclaredField(fieldName).getBoolean(null); - } + private void registerPluginChannels() { + Server server = Bukkit.getServer(); - private boolean isVelocityEnabled() - throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException, ClassNotFoundException, - NoSuchMethodException, InvocationTargetException { - try { - Class globalConfig = Class.forName("io.papermc.paper.configuration.GlobalConfiguration"); - Object global = globalConfig.getDeclaredMethod("get").invoke(null); - Object proxiesConfiguration = global.getClass().getDeclaredField("proxies").get(global); + // check for incoming messages from the bungeecord version of this plugin + String groupId = plugin.getName(); + String forceChannel = NamespaceKey.getCombined(groupId, LoginActionMessage.FORCE_CHANNEL); + server.getMessenger().registerIncomingPluginChannel(plugin, forceChannel, new ProxyListener(plugin, verifier)); - Field velocitySectionField = proxiesConfiguration.getClass().getDeclaredField("velocity"); - Object velocityConfig = velocitySectionField.get(proxiesConfiguration); + // outgoing + String successChannel = new NamespaceKey(groupId, SUCCESS_CHANNEL).getCombinedName(); + String changeChannel = new NamespaceKey(groupId, CHANGE_CHANNEL).getCombinedName(); + server.getMessenger().registerOutgoingPluginChannel(plugin, successChannel); + server.getMessenger().registerOutgoingPluginChannel(plugin, changeChannel); + } - return velocityConfig.getClass().getDeclaredField("enabled").getBoolean(velocityConfig); - } catch (ClassNotFoundException classNotFoundException) { - // try again using the older Paper configuration, because the old class file still exists in newer versions - if (isProxySupported("com.destroystokyo.paper.PaperConfig", "velocitySupport")) { - return true; - } + @Override + public void stop() { + if (verifier != null) { + verifier.cleanup(); } - - return false; } private boolean detectProxy() { @@ -155,82 +116,40 @@ private boolean detectProxy() { return false; } - private void registerPluginChannels() { - Server server = Bukkit.getServer(); - - // check for incoming messages from the bungeecord version of this plugin - String groupId = plugin.getName(); - String forceChannel = NamespaceKey.getCombined(groupId, LoginActionMessage.FORCE_CHANNEL); - server.getMessenger().registerIncomingPluginChannel(plugin, forceChannel, new BungeeListener(plugin)); - - // outgoing - String successChannel = new NamespaceKey(groupId, SUCCESS_CHANNEL).getCombinedName(); - String changeChannel = new NamespaceKey(groupId, CHANGE_CHANNEL).getCombinedName(); - server.getMessenger().registerOutgoingPluginChannel(plugin, successChannel); - server.getMessenger().registerOutgoingPluginChannel(plugin, changeChannel); + private boolean isProxySupported(String className, String fieldName) + throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { + return Class.forName(className).getDeclaredField(fieldName).getBoolean(null); } - private Set loadBungeeCordIds() { - Path proxiesFile = plugin.getPluginFolder().resolve(FILE_NAME); - Path legacyFile = plugin.getPluginFolder().resolve(LEGACY_FILE_NAME); + private boolean isVelocityEnabled() + throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException, ClassNotFoundException, + NoSuchMethodException, InvocationTargetException { try { - if (Files.notExists(proxiesFile)) { - if (Files.exists(legacyFile)) { - Files.move(legacyFile, proxiesFile); - } - - if (Files.notExists(legacyFile)) { - Files.createFile(proxiesFile); - } - } + Class globalConfig = Class.forName("io.papermc.paper.configuration.GlobalConfiguration"); + Object global = globalConfig.getDeclaredMethod("get").invoke(null); + Object proxiesConfiguration = global.getClass().getDeclaredField("proxies").get(global); - Files.deleteIfExists(legacyFile); - try (Stream lines = Files.lines(proxiesFile)) { - return lines.map(String::trim).map(UUID::fromString).collect(toSet()); + Field velocitySectionField = proxiesConfiguration.getClass().getDeclaredField("velocity"); + Object velocityConfig = velocitySectionField.get(proxiesConfiguration); + + return velocityConfig.getClass().getDeclaredField("enabled").getBoolean(velocityConfig); + } catch (ClassNotFoundException classNotFoundException) { + // try again using the older Paper configuration, because the old class file still exists in newer versions + if (isProxySupported("com.destroystokyo.paper.PaperConfig", "velocitySupport")) { + return true; } - } catch (IOException ex) { - plugin.getLog().error("Failed to read proxies", ex); - } catch (Exception ex) { - plugin.getLog().error("Failed to retrieve proxy Id. Disabling BungeeCord support", ex); } - return Collections.emptySet(); - } - - public boolean isProxyAllowed(UUID proxyId) { - return proxyIds != null && proxyIds.contains(proxyId); - } - - /** - * Mark the event to be fired including the task delay. - * - * @param player joining player - */ - public synchronized void markJoinEventFired(Player player) { - firedJoinEvents.add(player.getUniqueId()); + return false; } - /** - * Check if the event fired including with the task delay. This necessary to restore the order of processing the - * BungeeCord messages after the PlayerJoinEvent fires including the delay. - *

- * If the join event fired, the delay exceeded, but it ran earlier and couldn't find the recently started login - * session. If not fired, we can start a new force login task. This will still match the requirement that we wait - * a certain time after the player join event fired. - * - * @param player joining player - * @return event fired including delay - */ - public synchronized boolean didJoinEventFired(Player player) { - return firedJoinEvents.contains(player.getUniqueId()); - } + public void sendPluginMessage(PluginMessageRecipient player, ChannelMessage message) { + if (player != null) { + ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput(); + message.writeTo(dataOutput); - /** - * Player quit clean up - * - * @param player joining player - */ - public synchronized void cleanup(Player player) { - firedJoinEvents.remove(player.getUniqueId()); + NamespaceKey channel = new NamespaceKey(plugin.getName(), message.getChannelName()); + player.sendPluginMessage(plugin, channel.getCombinedName(), dataOutput.toByteArray()); + } } } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/proxy/ProxyConnectionListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/proxy/ProxyConnectionListener.java new file mode 100644 index 000000000..40ae9a9fa --- /dev/null +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/proxy/ProxyConnectionListener.java @@ -0,0 +1,114 @@ +/* + * SPDX-License-Identifier: MIT + * + * The MIT License (MIT) + * + * Copyright (c) 2015-2024 games647 and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.games647.fastlogin.bukkit.auth.proxy; + +import com.github.games647.fastlogin.bukkit.BukkitLoginSession; +import com.github.games647.fastlogin.bukkit.FastLoginBukkit; +import com.github.games647.fastlogin.bukkit.auth.FloodgateAuthTask; +import com.github.games647.fastlogin.bukkit.auth.ForceLoginTask; +import com.github.games647.fastlogin.core.hooks.bedrock.FloodgateService; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.metadata.Metadatable; +import org.geysermc.floodgate.api.player.FloodgatePlayer; + +public class ProxyConnectionListener implements Listener { + + private static final long DELAY_LOGIN = 20L / 2; + + private final FastLoginBukkit plugin; + private final ProxyVerifier verifier; + + public ProxyConnectionListener(FastLoginBukkit plugin, ProxyVerifier verifier) { + this.plugin = plugin; + this.verifier = verifier; + } + + private void removeBlockedStatus(Metadatable player) { + player.removeMetadata(plugin.getName(), plugin); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerLogin(PlayerLoginEvent loginEvent) { + removeBlockedStatus(loginEvent.getPlayer()); + } + + @EventHandler(ignoreCancelled = true) + public void onPlayerJoin(PlayerJoinEvent joinEvent) { + Player player = joinEvent.getPlayer(); + + Bukkit.getScheduler().runTaskLater(plugin, () -> { + delayForceLogin(player); + // delay the login process to let auth plugins initialize the player + // Magic number however as there is no direct event from those plugins + }, DELAY_LOGIN); + } + + private void delayForceLogin(Player player) { + // session exists so the player is ready for force login + // cases: Paper (firing BungeeCord message before PlayerJoinEvent) or not running BungeeCord and already + // having the login session from the login process + BukkitLoginSession session = plugin.getSession(player.spigot().getRawAddress()); + + if (session == null) { + // Floodgate players usually don't have a session at this point + // exception: if force login by bungee message had been delayed + FloodgateService floodgateService = plugin.getFloodgateService(); + if (floodgateService != null) { + FloodgatePlayer floodgatePlayer = floodgateService.getBedrockPlayer(player.getUniqueId()); + if (floodgatePlayer != null) { + Runnable floodgateAuthTask = new FloodgateAuthTask(plugin.getCore(), player, floodgatePlayer); + Bukkit.getScheduler().runTaskAsynchronously(plugin, floodgateAuthTask); + return; + } + } + + String sessionId = plugin.getSessionId(player.spigot().getRawAddress()); + plugin.getLog().info("No on-going login session for player: {} with ID {}. ", player, sessionId); + plugin.getLog().info("Setups using Minecraft proxies will start delayed " + + "when the command from the proxy is received"); + } else { + Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session); + Bukkit.getScheduler().runTaskAsynchronously(plugin, forceLoginTask); + } + + verifier.markJoinEventFired(player); + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent quitEvent) { + Player player = quitEvent.getPlayer(); + + removeBlockedStatus(player); + verifier.cleanup(player); + } +} diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/proxy/ProxyListener.java similarity index 92% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeListener.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/proxy/ProxyListener.java index 14cc9fa73..69884d33b 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/proxy/ProxyListener.java @@ -23,11 +23,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener; +package com.github.games647.fastlogin.bukkit.auth.proxy; import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.bukkit.task.ForceLoginTask; +import com.github.games647.fastlogin.bukkit.auth.ForceLoginTask; import com.github.games647.fastlogin.core.PremiumStatus; import com.github.games647.fastlogin.core.hooks.AuthPlugin; import com.github.games647.fastlogin.core.message.LoginActionMessage; @@ -47,12 +47,14 @@ * This class also receives the plugin message from the bungeecord version of this plugin in order to get notified if * the connection is in online mode. */ -public class BungeeListener implements PluginMessageListener { +public class ProxyListener implements PluginMessageListener { private final FastLoginBukkit plugin; + private final ProxyVerifier verifier; - public BungeeListener(FastLoginBukkit plugin) { + public ProxyListener(FastLoginBukkit plugin, ProxyVerifier verifier) { this.plugin = plugin; + this.verifier = verifier; } @Override @@ -79,7 +81,7 @@ public void onPluginMessageReceived(@NotNull String channel, Player player, byte plugin.getLog().warn("Received message {} from a blocked player {}", loginMessage, targetPlayer); } else { UUID sourceId = loginMessage.getProxyId(); - if (plugin.getBungeeManager().isProxyAllowed(sourceId)) { + if (verifier.isProxyAllowed(sourceId)) { readMessage(targetPlayer, loginMessage); } else { plugin.getLog().warn("Received proxy id: {} that doesn't exist in the proxy file", sourceId); @@ -127,7 +129,7 @@ private void startLoginTaskIfReady(Player player, BukkitLoginSession session) { plugin.putSession(player.spigot().getRawAddress(), session); // only start a new login task if the join event fired earlier. This event then didn't - boolean result = plugin.getBungeeManager().didJoinEventFired(player); + boolean result = verifier.didJoinEventFired(player); plugin.getLog().info("Delaying force login until join event fired?: {}", result); if (result) { Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session); diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/proxy/ProxyVerifier.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/proxy/ProxyVerifier.java new file mode 100644 index 000000000..0f94c5d2c --- /dev/null +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/auth/proxy/ProxyVerifier.java @@ -0,0 +1,135 @@ +/* + * SPDX-License-Identifier: MIT + * + * The MIT License (MIT) + * + * Copyright (c) 2015-2024 games647 and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.github.games647.fastlogin.bukkit.auth.proxy; + +import com.github.games647.fastlogin.bukkit.FastLoginBukkit; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toSet; + +public class ProxyVerifier { + + private static final String LEGACY_FILE_NAME = "proxy-whitelist.txt"; + private static final String FILE_NAME = "allowed-proxies.txt"; + + //null if proxies allowed list is empty so bungeecord support is disabled + private Set proxyIds; + + private final FastLoginBukkit plugin; + + private final Collection firedJoinEvents = new HashSet<>(); + + public ProxyVerifier(FastLoginBukkit plugin) { + this.plugin = plugin; + } + + public void cleanup() { + //remove old blocked status + Bukkit.getOnlinePlayers().forEach(player -> player.removeMetadata(plugin.getName(), plugin)); + } + + public void loadSecrets() { + proxyIds = loadBungeeCordIds(); + if (proxyIds.isEmpty()) { + plugin.getLog().info("No valid IDs found. Minecraft proxy support cannot work in the current state"); + } + } + + private Set loadBungeeCordIds() { + Path proxiesFile = plugin.getPluginFolder().resolve(FILE_NAME); + Path legacyFile = plugin.getPluginFolder().resolve(LEGACY_FILE_NAME); + try { + if (Files.notExists(proxiesFile)) { + if (Files.exists(legacyFile)) { + Files.move(legacyFile, proxiesFile); + } + + if (Files.notExists(legacyFile)) { + Files.createFile(proxiesFile); + } + } + + Files.deleteIfExists(legacyFile); + try (Stream lines = Files.lines(proxiesFile)) { + return lines.map(String::trim).map(UUID::fromString).collect(toSet()); + } + } catch (IOException ex) { + plugin.getLog().error("Failed to read proxies", ex); + } catch (Exception ex) { + plugin.getLog().error("Failed to retrieve proxy Id. Disabling BungeeCord support", ex); + } + + return Collections.emptySet(); + } + + public boolean isProxyAllowed(UUID proxyId) { + return proxyIds != null && proxyIds.contains(proxyId); + } + + /** + * Mark the event to be fired including the task delay. + * + * @param player joining player + */ + public synchronized void markJoinEventFired(Player player) { + firedJoinEvents.add(player.getUniqueId()); + } + + /** + * Check if the event fired including with the task delay. This necessary to restore the order of processing the + * BungeeCord messages after the PlayerJoinEvent fires including the delay. + *

+ * If the join event fired, the delay exceeded, but it ran earlier and couldn't find the recently started login + * session. If not fired, we can start a new force login task. This will still match the requirement that we wait + * a certain time after the player join event fired. + * + * @param player joining player + * @return event fired including delay + */ + public synchronized boolean didJoinEventFired(Player player) { + return firedJoinEvents.contains(player.getUniqueId()); + } + + /** + * Player quit clean up + * + * @param player joining player + */ + public synchronized void cleanup(Player player) { + firedJoinEvents.remove(player.getUniqueId()); + } +} diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/PremiumCommand.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/PremiumCommand.java index 6f132271a..37aac05be 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/PremiumCommand.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/PremiumCommand.java @@ -64,18 +64,18 @@ private void onPremiumSelf(CommandSender sender) { return; } - if (forwardPremiumCommand(sender, sender.getName())) { + UUID id = ((Player) sender).getUniqueId(); + if (plugin.getConfig().getBoolean("premium-warning") && !plugin.getPendingConfirms().contains(id)) { + sender.sendMessage(plugin.getCore().getMessage("premium-warning")); + plugin.getPendingConfirms().add(id); return; } - UUID id = ((Player) sender).getUniqueId(); - if (plugin.getConfig().getBoolean("premium-warning") && !plugin.getCore().getPendingConfirms().contains(id)) { - sender.sendMessage(plugin.getCore().getMessage("premium-warning")); - plugin.getCore().getPendingConfirms().add(id); + if (forwardPremiumCommand(sender, sender.getName())) { return; } - plugin.getCore().getPendingConfirms().remove(id); + plugin.getPendingConfirms().remove(id); //todo: load async StoredProfile profile = plugin.getCore().getStorage().loadProfile(sender.getName()); if (profile.isOnlinemodePreferred()) { diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/ToggleCommand.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/ToggleCommand.java index 47aa5cfc5..12c292313 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/ToggleCommand.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/ToggleCommand.java @@ -26,6 +26,7 @@ package com.github.games647.fastlogin.bukkit.command; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; +import com.github.games647.fastlogin.bukkit.auth.proxy.ProxyAuthentication; import com.github.games647.fastlogin.core.message.ChangePremiumMessage; import com.github.games647.fastlogin.core.message.ChannelMessage; import org.bukkit.Bukkit; @@ -55,7 +56,7 @@ protected boolean hasOtherPermission(CommandSender sender, Command cmd) { } protected boolean forwardBungeeCommand(CommandSender sender, String target, boolean activate) { - if (plugin.getBungeeManager().isEnabled()) { + if (plugin.getBackend() instanceof ProxyAuthentication) { sendBungeeActivateMessage(sender, target, activate); plugin.getCore().sendLocaleMessage("wait-on-proxy", sender); return true; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/task/DelayedAuthHook.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/DelayedAuthHook.java similarity index 79% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/task/DelayedAuthHook.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/DelayedAuthHook.java index 510fa614b..b2abb3fd9 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/task/DelayedAuthHook.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/DelayedAuthHook.java @@ -23,15 +23,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.task; +package com.github.games647.fastlogin.bukkit.hook; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.bukkit.hook.AuthMeHook; -import com.github.games647.fastlogin.bukkit.hook.CrazyLoginHook; -import com.github.games647.fastlogin.bukkit.hook.LogItHook; -import com.github.games647.fastlogin.bukkit.hook.LoginSecurityHook; -import com.github.games647.fastlogin.bukkit.hook.UltraAuthHook; -import com.github.games647.fastlogin.bukkit.hook.XAuthHook; import com.github.games647.fastlogin.core.hooks.AuthPlugin; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -51,19 +45,7 @@ public DelayedAuthHook(FastLoginBukkit plugin) { @Override public void run() { - boolean hookFound = isHookFound(); - if (plugin.getBungeeManager().isEnabled()) { - plugin.getLog().info("BungeeCord setting detected. No auth plugin is required"); - } else if (!hookFound) { - plugin.getLog().warn("No auth plugin were found by this plugin " - + "(other plugins could hook into this after the initialization of this plugin)" - + "and BungeeCord is deactivated. " - + "Either one or both of the checks have to pass in order to use this plugin"); - } - - if (hookFound) { - plugin.markInitialized(); - } + plugin.setInitialized(isHookFound()); } private boolean isHookFound() { diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolSupportListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolSupportListener.java deleted file mode 100644 index 5e5139457..000000000 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolSupportListener.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * The MIT License (MIT) - * - * Copyright (c) 2015-2024 games647 and contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.github.games647.fastlogin.bukkit.listener.protocolsupport; - -import com.github.games647.craftapi.UUIDAdapter; -import com.github.games647.fastlogin.bukkit.BukkitLoginSession; -import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPreLoginEvent; -import com.github.games647.fastlogin.core.antibot.AntiBotService; -import com.github.games647.fastlogin.core.antibot.AntiBotService.Action; -import com.github.games647.fastlogin.core.shared.JoinManagement; -import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent; -import com.github.games647.fastlogin.core.storage.StoredProfile; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import protocolsupport.api.events.ConnectionCloseEvent; -import protocolsupport.api.events.PlayerLoginStartEvent; -import protocolsupport.api.events.PlayerProfileCompleteEvent; - -import java.net.InetSocketAddress; -import java.util.Optional; - -public class ProtocolSupportListener extends JoinManagement - implements Listener { - - private final FastLoginBukkit plugin; - private final AntiBotService antiBotService; - - public ProtocolSupportListener(FastLoginBukkit plugin, AntiBotService antiBotService) { - super(plugin.getCore(), plugin.getCore().getAuthPluginHook(), plugin.getBedrockService()); - - this.plugin = plugin; - this.antiBotService = antiBotService; - } - - @EventHandler - public void onLoginStart(PlayerLoginStartEvent loginStartEvent) { - if (loginStartEvent.isLoginDenied() || plugin.getCore().getAuthPluginHook() == null) { - return; - } - - String username = loginStartEvent.getConnection().getProfile().getName(); - InetSocketAddress address = loginStartEvent.getConnection().getRawAddress(); - plugin.getLog().info("Incoming login request for {} from {}", username, address); - - Action action = antiBotService.onIncomingConnection(address, username); - switch (action) { - case Ignore: - // just ignore - return; - case Block: - String message = plugin.getCore().getMessage("kick-antibot"); - loginStartEvent.denyLogin(message); - break; - case Continue: - default: - //remove old data every time on a new login in order to keep the session only for one person - plugin.removeSession(address); - - ProtocolLoginSource source = new ProtocolLoginSource(loginStartEvent); - super.onLogin(username, source); - break; - } - } - - @EventHandler - public void onConnectionClosed(ConnectionCloseEvent closeEvent) { - InetSocketAddress address = closeEvent.getConnection().getRawAddress(); - plugin.removeSession(address); - } - - @EventHandler - public void onPropertiesResolve(PlayerProfileCompleteEvent profileCompleteEvent) { - InetSocketAddress address = profileCompleteEvent.getConnection().getRawAddress(); - - BukkitLoginSession session = plugin.getSession(address); - - if (session != null && profileCompleteEvent.getConnection().getProfile().isOnlineMode()) { - session.setVerifiedPremium(true); - - if (!plugin.getConfig().getBoolean("premiumUuid")) { - String username = Optional.ofNullable(profileCompleteEvent.getForcedName()) - .orElse(profileCompleteEvent.getConnection().getProfile().getName()); - profileCompleteEvent.setForcedUUID(UUIDAdapter.generateOfflineId(username)); - } - } - } - - @Override - public FastLoginPreLoginEvent callFastLoginPreLoginEvent(String username, ProtocolLoginSource source, - StoredProfile profile) { - BukkitFastLoginPreLoginEvent event = new BukkitFastLoginPreLoginEvent(username, source, profile); - plugin.getServer().getPluginManager().callEvent(event); - return event; - } - - @Override - public void requestPremiumLogin(ProtocolLoginSource source, StoredProfile profile, String username, - boolean registered) { - source.enableOnlinemode(); - - String ip = source.getAddress().getAddress().getHostAddress(); - plugin.getCore().addLoginAttempt(ip, username); - - BukkitLoginSession playerSession = new BukkitLoginSession(username, registered, profile); - plugin.putSession(source.getAddress(), playerSession); - } - - @Override - public void startCrackedSession(ProtocolLoginSource source, StoredProfile profile, String username) { - BukkitLoginSession loginSession = new BukkitLoginSession(username, profile); - plugin.putSession(source.getAddress(), loginSession); - } -} diff --git a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/Base64Adapter.java b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/Base64Adapter.java similarity index 96% rename from bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/Base64Adapter.java rename to bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/Base64Adapter.java index 7376ef99d..6f1c2cc8b 100644 --- a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/Base64Adapter.java +++ b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/Base64Adapter.java @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener.protocollib; +package com.github.games647.fastlogin.bukkit.auth.protocollib; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; diff --git a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/EncryptionUtilTest.java similarity index 86% rename from bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java rename to bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/EncryptionUtilTest.java index 4b7a80244..5bb469c07 100644 --- a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java +++ b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/EncryptionUtilTest.java @@ -23,10 +23,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener.protocollib; +package com.github.games647.fastlogin.bukkit.auth.protocollib; -import com.github.games647.fastlogin.bukkit.listener.protocollib.SignatureTestData.SignatureData; -import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey; +import com.github.games647.fastlogin.bukkit.auth.protocollib.SignatureTestData.SignatureData; +import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey; import com.google.common.hash.Hashing; import lombok.val; import org.junit.jupiter.api.Test; @@ -60,7 +60,7 @@ class EncryptionUtilTest { @Test void testVerifyToken() { - val random = ThreadLocalRandom.current(); + @SuppressWarnings("SharedThreadLocalRandom") val random = ThreadLocalRandom.current(); byte[] token = EncryptionUtil.generateVerifyToken(random); assertAll( @@ -88,7 +88,7 @@ void testServerKey() { @Test void testExpiredClientKey() throws Exception { - val clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json"); + val clientKey = com.github.games647.fastlogin.bukkit.auth.protocollib.ResourceLoader.loadClientKey("client_keys/valid_public_key.json"); // Client expires at the exact second mentioned, so use it for verification val expiredTimestamp = clientKey.expiry(); @@ -105,7 +105,7 @@ void testExpiredClientKey() throws Exception { "client_keys/invalid_wrong_signature.json" }) void testInvalidClientKey(String clientKeySource) throws Exception { - val clientKey = ResourceLoader.loadClientKey(clientKeySource); + val clientKey = com.github.games647.fastlogin.bukkit.auth.protocollib.ResourceLoader.loadClientKey(clientKeySource); Instant expireTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS); assertFalse(EncryptionUtil.verifyClientKey(clientKey, expireTimestamp, null)); @@ -113,7 +113,7 @@ void testInvalidClientKey(String clientKeySource) throws Exception { @Test void testValidClientKey() throws Exception { - val clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json"); + val clientKey = com.github.games647.fastlogin.bukkit.auth.protocollib.ResourceLoader.loadClientKey("client_keys/valid_public_key.json"); val verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS); assertTrue(EncryptionUtil.verifyClientKey(clientKey, verificationTimestamp, null)); @@ -121,7 +121,7 @@ void testValidClientKey() throws Exception { @Test void testValid191ClientKey() throws Exception { - val clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key_19_1.json"); + val clientKey = com.github.games647.fastlogin.bukkit.auth.protocollib.ResourceLoader.loadClientKey("client_keys/valid_public_key_19_1.json"); val verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS); val ownerPremiumId = UUID.fromString("0aaa2c13-922a-411b-b655-9b8c08404695"); @@ -130,7 +130,7 @@ void testValid191ClientKey() throws Exception { @Test void testIncorrect191ClientOwner() throws Exception { - val clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key_19_1.json"); + val clientKey = com.github.games647.fastlogin.bukkit.auth.protocollib.ResourceLoader.loadClientKey("client_keys/valid_public_key_19_1.json"); val verificationTimestamp = clientKey.expiry().minus(5, ChronoUnit.HOURS); val ownerPremiumId = UUID.fromString("61699b2e-d327-4a01-9f1e-0ea8c3f06bc6"); @@ -170,7 +170,7 @@ private static SecretKeySpec generateSharedKey() { void testServerIdHash() throws Exception { val serverId = ""; val sharedSecret = generateSharedKey(); - val serverPK = ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key(); + val serverPK = com.github.games647.fastlogin.bukkit.auth.protocollib.ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key(); String sessionHash = getServerHash(serverId, sharedSecret, serverPK); assertEquals(EncryptionUtil.getServerIdHashString(serverId, sharedSecret, serverPK), sessionHash); @@ -200,7 +200,7 @@ private static String getServerHash(@SuppressWarnings("SameParameterValue") Char void testServerIdHashWrongSecret() throws Exception { val serverId = ""; val sharedSecret = generateSharedKey(); - val serverPK = ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key(); + val serverPK = com.github.games647.fastlogin.bukkit.auth.protocollib.ResourceLoader.loadClientKey("client_keys/valid_public_key.json").key(); String sessionHash = getServerHash(serverId, sharedSecret, serverPK); assertNotEquals(EncryptionUtil.getServerIdHashString("", generateSharedKey(), serverPK), sessionHash); @@ -219,7 +219,7 @@ void testServerIdHashWrongServerKey() { @Test void testValidSignedNonce() throws Exception { - ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json"); + ClientPublicKey clientKey = com.github.games647.fastlogin.bukkit.auth.protocollib.ResourceLoader.loadClientKey("client_keys/valid_public_key.json"); SignatureTestData testData = SignatureTestData.fromResource("signature/valid_signature.json"); assertTrue(verifySignedNonce(testData, clientKey)); } @@ -231,7 +231,7 @@ void testValidSignedNonce() throws Exception { "signature/incorrect_signature.json", }) void testIncorrectNonce(String signatureSource) throws Exception { - ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/valid_public_key.json"); + ClientPublicKey clientKey = com.github.games647.fastlogin.bukkit.auth.protocollib.ResourceLoader.loadClientKey("client_keys/valid_public_key.json"); SignatureTestData testData = SignatureTestData.fromResource(signatureSource); assertFalse(verifySignedNonce(testData, clientKey)); } @@ -239,7 +239,7 @@ void testIncorrectNonce(String signatureSource) throws Exception { @Test void testWrongPublicKeySigned() throws Exception { // load a different public key - ClientPublicKey clientKey = ResourceLoader.loadClientKey("client_keys/invalid_wrong_key.json"); + ClientPublicKey clientKey = com.github.games647.fastlogin.bukkit.auth.protocollib.ResourceLoader.loadClientKey("client_keys/invalid_wrong_key.json"); SignatureTestData testData = SignatureTestData.fromResource("signature/valid_signature.json"); assertFalse(verifySignedNonce(testData, clientKey)); } diff --git a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ResourceLoader.java b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/ResourceLoader.java similarity index 95% rename from bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ResourceLoader.java rename to bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/ResourceLoader.java index 792d216ce..f4b16c8fb 100644 --- a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ResourceLoader.java +++ b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/ResourceLoader.java @@ -23,9 +23,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener.protocollib; +package com.github.games647.fastlogin.bukkit.auth.protocollib; -import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey; +import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey; import com.google.common.io.Resources; import com.google.gson.Gson; import com.google.gson.JsonObject; @@ -50,6 +50,10 @@ public class ResourceLoader { + private ResourceLoader() { + // Utility + } + public static RSAPrivateKey parsePrivateKey(String keySpec) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { try ( diff --git a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SignatureTestData.java b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/SignatureTestData.java similarity index 97% rename from bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SignatureTestData.java rename to bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/SignatureTestData.java index 937c72b0d..6306942af 100644 --- a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SignatureTestData.java +++ b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/SignatureTestData.java @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener.protocollib; +package com.github.games647.fastlogin.bukkit.auth.protocollib; import com.google.common.io.Resources; import com.google.gson.Gson; diff --git a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTaskTest.java b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/VerifyResponseTaskTest.java similarity index 97% rename from bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTaskTest.java rename to bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/VerifyResponseTaskTest.java index 8309aecf2..ce93d668d 100644 --- a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTaskTest.java +++ b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/auth/protocollib/VerifyResponseTaskTest.java @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.listener.protocollib; +package com.github.games647.fastlogin.bukkit.auth.protocollib; import com.comphenix.protocol.injector.packet.PacketRegistry; import com.comphenix.protocol.reflect.accessors.Accessors; diff --git a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/task/DelayedAuthHookTest.java b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/hook/DelayedAuthHookTest.java similarity index 97% rename from bukkit/src/test/java/com/github/games647/fastlogin/bukkit/task/DelayedAuthHookTest.java rename to bukkit/src/test/java/com/github/games647/fastlogin/bukkit/hook/DelayedAuthHookTest.java index a829a4ddf..28a22cbab 100644 --- a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/task/DelayedAuthHookTest.java +++ b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/hook/DelayedAuthHookTest.java @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.github.games647.fastlogin.bukkit.task; +package com.github.games647.fastlogin.bukkit.hook; import com.github.games647.fastlogin.core.hooks.AuthPlugin; import lombok.val; diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/ConnectListener.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/ConnectListener.java index afdd6a7e5..eb389b633 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/ConnectListener.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/ConnectListener.java @@ -233,9 +233,6 @@ public void onServerConnected(ServerConnectedEvent serverConnectedEvent) { return; } - // delay sending force command, because Paper will process the login event asynchronously - // In this case it means that the force command (plugin message) is already received and processed while - // player is still in the login phase and reported to be offline. Runnable loginTask = new ForceLoginTask(plugin.getCore(), player, server, session); plugin.getScheduler().runAsync(loginTask); } @@ -244,6 +241,5 @@ public void onServerConnected(ServerConnectedEvent serverConnectedEvent) { public void onDisconnect(PlayerDisconnectEvent disconnectEvent) { ProxiedPlayer player = disconnectEvent.getPlayer(); plugin.getSession().remove(player.getPendingConnection()); - plugin.getCore().getPendingConfirms().remove(player.getUniqueId()); } } diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PluginMessageListener.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PluginMessageListener.java index bb4ca89d8..79c8dd927 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PluginMessageListener.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PluginMessageListener.java @@ -37,7 +37,6 @@ import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteStreams; import net.md_5.bungee.api.CommandSender; -import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.Server; import net.md_5.bungee.api.event.PluginMessageEvent; @@ -96,15 +95,6 @@ private void readMessage(ProxiedPlayer forPlayer, String channel, byte[] data) { String playerName = changeMessage.getPlayerName(); boolean isSourceInvoker = changeMessage.isSourceInvoker(); if (changeMessage.shouldEnable()) { - if (playerName.equals(forPlayer.getName()) && plugin.getCore().getConfig().get("premium-warning", true) - && !core.getPendingConfirms().contains(forPlayer.getUniqueId())) { - String message = core.getMessage("premium-warning"); - forPlayer.sendMessage(TextComponent.fromLegacyText(message)); - core.getPendingConfirms().add(forPlayer.getUniqueId()); - return; - } - - core.getPendingConfirms().remove(forPlayer.getUniqueId()); Runnable task = new AsyncToggleMessage(core, forPlayer, playerName, true, isSourceInvoker); plugin.getScheduler().runAsync(task); } else { diff --git a/core/pom.xml b/core/pom.xml index cfea327aa..c56a90599 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -125,7 +125,7 @@ com.zaxxer HikariCP - 4.0.3 + 5.1.0 @@ -203,7 +203,7 @@ com.github.games647 craftapi - 0.8.1 + 1.0-SNAPSHOT diff --git a/core/src/main/java/com/github/games647/fastlogin/core/ProxyAgnosticMojangResolver.java b/core/src/main/java/com/github/games647/fastlogin/core/ProxyAgnosticMojangResolver.java index e57680378..f3719dd22 100644 --- a/core/src/main/java/com/github/games647/fastlogin/core/ProxyAgnosticMojangResolver.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/ProxyAgnosticMojangResolver.java @@ -29,8 +29,6 @@ import com.github.games647.craftapi.resolver.MojangResolver; import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; import java.net.InetAddress; import java.util.Optional; @@ -44,38 +42,9 @@ */ public class ProxyAgnosticMojangResolver extends MojangResolver { - private static final String HOST = "sessionserver.mojang.com"; - - /** - * A formatting string containing a URL used to call the {@code hasJoined} method on mojang session servers. - *

- * Formatting parameters: - * 1. The username of the player in question - * 2. The serverId of this server - */ - public static final String ENDPOINT = "https://" + HOST + "/session/minecraft/hasJoined?username=%s&serverId=%s"; - @Override public Optional hasJoined(String username, String serverHash, InetAddress hostIp) throws IOException { - String url = String.format(ENDPOINT, username, serverHash); - - HttpURLConnection conn = this.getConnection(url); - int responseCode = conn.getResponseCode(); - - Verification verification = null; - - // Mojang session servers send HTTP 204 (NO CONTENT) when the authentication seems invalid - // If that's not our case, the authentication is valid, and so we can parse the response. - if (responseCode != HttpURLConnection.HTTP_NO_CONTENT) { - verification = this.parseRequest(conn, this::parseVerification); - } - - return Optional.ofNullable(verification); - } - - // Functional implementation of InputStreamAction, used in hasJoined method in parseRequest call - protected Verification parseVerification(InputStream input) throws IOException { - return this.readJson(input, Verification.class); + return super.hasJoined(username, serverHash, null); } } diff --git a/core/src/main/java/com/github/games647/fastlogin/core/shared/FastLoginCore.java b/core/src/main/java/com/github/games647/fastlogin/core/shared/FastLoginCore.java index c1fca7db3..cb476afa3 100644 --- a/core/src/main/java/com/github/games647/fastlogin/core/shared/FastLoginCore.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/shared/FastLoginCore.java @@ -61,7 +61,6 @@ import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -83,7 +82,6 @@ public class FastLoginCore

> { Duration.ofMinutes(5), -1 ); - private final Collection pendingConfirms = new HashSet<>(); private final T plugin; private MojangResolver resolver; @@ -123,7 +121,7 @@ public void load() { // Initialize the resolver based on the config parameter this.resolver = this.config.getBoolean("useProxyAgnosticResolver", false) - ? new ProxyAgnosticMojangResolver() : new MojangResolver(); + ? new ProxyAgnosticMojangResolver() : new MojangResolver(); antiBot = createAntiBotService(config.getSection("anti-bot")); Set proxies = config.getStringList("proxies") @@ -144,7 +142,6 @@ public void load() { resolver.setMaxNameRequests(config.getInt("mojang-request-limit")); resolver.setProxySelector(new RotatingProxySelector(proxies)); - resolver.setOutgoingAddresses(addresses); } private AntiBotService createAntiBotService(Configuration botSection) { @@ -164,12 +161,12 @@ private AntiBotService createAntiBotService(Configuration botSection) { Action action = Action.Ignore; switch (botSection.getString("action", "ignore")) { - case "ignore": - action = Action.Ignore; - break; case "block": action = Action.Block; break; + case "ignore": + action = Action.Ignore; + break; default: plugin.getLog().warn("Invalid anti bot action - defaulting to ignore"); } @@ -288,10 +285,6 @@ public boolean hasFailedLogin(String ip, String username) { return pendingLogin.remove(ip + username) != null; } - public Collection getPendingConfirms() { - return pendingConfirms; - } - public AuthPlugin

getAuthPluginHook() { return authPlugin; } diff --git a/core/src/main/java/com/github/games647/fastlogin/core/shared/JoinManagement.java b/core/src/main/java/com/github/games647/fastlogin/core/shared/JoinManagement.java index 73430c81c..853115360 100644 --- a/core/src/main/java/com/github/games647/fastlogin/core/shared/JoinManagement.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/shared/JoinManagement.java @@ -109,7 +109,7 @@ private void performNewPlayerLogin(String username, S source, String ip, StoredP premiumUUID = core.getResolver().findProfile(username); } - if (!premiumUUID.isPresent() + if (premiumUUID.isPresent() || (!isNameChanged(source, username, premiumUUID.get()) && !isUsernameAvailable(source, username, profile))) { //nothing detected the player as premium -> start a cracked session diff --git a/core/src/main/java/com/github/games647/fastlogin/core/shared/LoginSource.java b/core/src/main/java/com/github/games647/fastlogin/core/shared/LoginSource.java index 4ce5cc5e7..eff001e72 100644 --- a/core/src/main/java/com/github/games647/fastlogin/core/shared/LoginSource.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/shared/LoginSource.java @@ -29,7 +29,7 @@ public interface LoginSource { - void enableOnlinemode() throws Exception; + void enableOnlinemode(); void kick(String message); diff --git a/core/src/main/java/com/github/games647/fastlogin/core/shared/PlatformPlugin.java b/core/src/main/java/com/github/games647/fastlogin/core/shared/PlatformPlugin.java index 46c431d3c..8a55b9dfa 100644 --- a/core/src/main/java/com/github/games647/fastlogin/core/shared/PlatformPlugin.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/shared/PlatformPlugin.java @@ -32,9 +32,12 @@ import java.nio.file.Path; import java.util.concurrent.ThreadFactory; +import java.util.regex.Pattern; public interface PlatformPlugin { + Pattern PATTERN = Pattern.compile("%nl%"); + String getName(); Path getPluginFolder(); @@ -48,7 +51,7 @@ public interface PlatformPlugin { boolean isPluginInstalled(String name); default void sendMultiLineMessage(C receiver, String message) { - for (String line : message.split("%nl%")) { + for (String line : PATTERN.split(message)) { sendMessage(receiver, line); } } diff --git a/core/src/main/java/com/github/games647/fastlogin/core/storage/StoredProfile.java b/core/src/main/java/com/github/games647/fastlogin/core/storage/StoredProfile.java index e80d9d12e..a2e2d60ba 100644 --- a/core/src/main/java/com/github/games647/fastlogin/core/storage/StoredProfile.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/storage/StoredProfile.java @@ -163,17 +163,16 @@ public synchronized void setLastLogin(Instant lastLogin) { } @Override - public synchronized boolean equals(Object o) { - if (this == o) { + public synchronized boolean equals(Object other) { + if (this == other) { return true; } - if (!(o instanceof StoredProfile)) { + if (!(other instanceof StoredProfile)) { return false; } - - StoredProfile that = (StoredProfile) o; - if (!super.equals(o)) { + StoredProfile that = (StoredProfile) other; + if (!super.equals(other)) { return false; } diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 3685a3ae3..ee51c5efb 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -173,22 +173,6 @@ premium-warning: true # every environment is different, and so it might not work for you as it did for me. useProxyAgnosticResolver: false -# If you have autoRegister or nameChangeCheck enabled, you could be rate-limited by Mojang. -# The requests of the both options will be only made by FastLogin if the username is unknown to the server -# You are allowed to make 600 requests per 10-minutes (60 per minute) -# If you own a big server this value could be too low -# Once the limit is reached, new players are always logged in as cracked until the rate-limit is expired. -# (to the next ten minutes) -# -# The limit is IP-wide. If you have multiple IPv4-addresses you specify them here. FastLogin will then use it in -# rotating order --> 5 different IP-addresses 5 * 600 per 10 minutes -# If this list is empty only the default one will be used -# -# Lists are created like this: -#ip-addresses: -# - 192-168-0-2 -ip-addresses: [] - # How many requests should be established to the Mojang API for Name -> UUID requests. Some other plugins as well # as the head Minecraft block make such requests as well. Using this option you can limit the amount requests this # plugin should make. diff --git a/core/src/test/java/com/github/games647/fastlogin/core/hooks/DefaultPasswordGeneratorTest.java b/core/src/test/java/com/github/games647/fastlogin/core/hooks/DefaultPasswordGeneratorTest.java index ba7cec331..a71693181 100644 --- a/core/src/test/java/com/github/games647/fastlogin/core/hooks/DefaultPasswordGeneratorTest.java +++ b/core/src/test/java/com/github/games647/fastlogin/core/hooks/DefaultPasswordGeneratorTest.java @@ -27,13 +27,13 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; class DefaultPasswordGeneratorTest { @Test void smokeTestPassword() { PasswordGenerator passwordGenerator = new DefaultPasswordGenerator<>(); - assertTrue(passwordGenerator.getRandomPassword(null).length() == 8); + assertEquals(8, passwordGenerator.getRandomPassword(null).length()); } } diff --git a/pom.xml b/pom.xml index d8062f67f..8187aaddd 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ Unknown - 8 + 11 1.18.32 diff --git a/velocity/src/main/java/com/github/games647/fastlogin/velocity/VelocityLoginSource.java b/velocity/src/main/java/com/github/games647/fastlogin/velocity/VelocityLoginSource.java index dfd98acb9..3468b0255 100644 --- a/velocity/src/main/java/com/github/games647/fastlogin/velocity/VelocityLoginSource.java +++ b/velocity/src/main/java/com/github/games647/fastlogin/velocity/VelocityLoginSource.java @@ -27,6 +27,7 @@ import com.github.games647.fastlogin.core.shared.LoginSource; import com.velocitypowered.api.event.connection.PreLoginEvent; +import com.velocitypowered.api.event.connection.PreLoginEvent.PreLoginComponentResult; import com.velocitypowered.api.proxy.InboundConnection; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -46,17 +47,17 @@ public VelocityLoginSource(InboundConnection connection, PreLoginEvent preLoginE @Override public void enableOnlinemode() { - preLoginEvent.setResult(PreLoginEvent.PreLoginComponentResult.forceOnlineMode()); + preLoginEvent.setResult(PreLoginComponentResult.forceOnlineMode()); } @Override public void kick(String message) { if (message == null) { - preLoginEvent.setResult(PreLoginEvent.PreLoginComponentResult.denied( + preLoginEvent.setResult(PreLoginComponentResult.denied( Component.text("Kicked").color(NamedTextColor.WHITE)) ); } else { - preLoginEvent.setResult(PreLoginEvent.PreLoginComponentResult.denied( + preLoginEvent.setResult(PreLoginComponentResult.denied( LegacyComponentSerializer.legacyAmpersand().deserialize(message)) ); } diff --git a/velocity/src/main/java/com/github/games647/fastlogin/velocity/event/VelocityFastLoginAutoLoginEvent.java b/velocity/src/main/java/com/github/games647/fastlogin/velocity/event/VelocityFastLoginAutoLoginEvent.java index 38346097d..d9f1a00c8 100644 --- a/velocity/src/main/java/com/github/games647/fastlogin/velocity/event/VelocityFastLoginAutoLoginEvent.java +++ b/velocity/src/main/java/com/github/games647/fastlogin/velocity/event/VelocityFastLoginAutoLoginEvent.java @@ -29,11 +29,12 @@ import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent; import com.github.games647.fastlogin.core.storage.StoredProfile; import com.velocitypowered.api.event.ResultedEvent; +import com.velocitypowered.api.event.ResultedEvent.GenericResult; import java.util.Objects; public class VelocityFastLoginAutoLoginEvent - implements FastLoginAutoLoginEvent, ResultedEvent { + implements FastLoginAutoLoginEvent, ResultedEvent { private final LoginSession session; private final StoredProfile profile; diff --git a/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java b/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java index e9c57369a..47705df17 100644 --- a/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java +++ b/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java @@ -38,7 +38,6 @@ import com.github.games647.fastlogin.velocity.task.ForceLoginTask; import com.velocitypowered.api.event.EventTask; import com.velocitypowered.api.event.Subscribe; -import com.velocitypowered.api.event.connection.DisconnectEvent; import com.velocitypowered.api.event.connection.PreLoginEvent; import com.velocitypowered.api.event.connection.PreLoginEvent.PreLoginComponentResult; import com.velocitypowered.api.event.player.GameProfileRequestEvent; @@ -46,14 +45,12 @@ import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.server.RegisteredServer; -import com.velocitypowered.api.util.GameProfile; import com.velocitypowered.api.util.GameProfile.Property; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.geysermc.floodgate.api.player.FloodgatePlayer; import java.net.InetSocketAddress; -import java.time.Duration; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -130,9 +127,9 @@ public void onGameProfileRequest(GameProfileRequestEvent event) { } } - private List removeSkin(Collection oldProperties) { - List newProperties = new ArrayList<>(oldProperties.size()); - for (GameProfile.Property property : oldProperties) { + private List removeSkin(Collection oldProperties) { + List newProperties = new ArrayList<>(oldProperties.size()); + for (Property property : oldProperties) { if (!"textures".equals(property.getName())) { newProperties.add(property); } @@ -169,12 +166,6 @@ public void onServerConnected(ServerConnectedEvent serverConnectedEvent) { Runnable loginTask = new ForceLoginTask(plugin.getCore(), player, server, session); // Delay at least one second, otherwise the login command can be missed - plugin.getScheduler().runAsyncDelayed(loginTask, Duration.ofSeconds(1)); - } - - @Subscribe - public void onDisconnect(DisconnectEvent disconnectEvent) { - Player player = disconnectEvent.getPlayer(); - plugin.getCore().getPendingConfirms().remove(player.getUniqueId()); + plugin.getScheduler().runAsync(loginTask); } } diff --git a/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/PluginMessageListener.java b/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/PluginMessageListener.java index 12b19f60a..69e3d5e45 100644 --- a/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/PluginMessageListener.java +++ b/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/PluginMessageListener.java @@ -38,10 +38,10 @@ import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.PluginMessageEvent; +import com.velocitypowered.api.event.connection.PluginMessageEvent.ForwardResult; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import java.util.Arrays; @@ -69,7 +69,7 @@ public void onPluginMessage(PluginMessageEvent pluginMessageEvent) { //the client shouldn't be able to read the messages in order to know something about server internal states //moreover the client shouldn't be able to fake a running premium check by sending the result message - pluginMessageEvent.setResult(PluginMessageEvent.ForwardResult.handled()); + pluginMessageEvent.setResult(ForwardResult.handled()); if (!(pluginMessageEvent.getSource() instanceof ServerConnection)) { //check if the message is sent from the server @@ -96,16 +96,6 @@ private void readMessage(Player forPlayer, String channel, byte[] data) { String playerName = changeMessage.getPlayerName(); boolean isSourceInvoker = changeMessage.isSourceInvoker(); if (changeMessage.shouldEnable()) { - Boolean premiumWarning = plugin.getCore().getConfig().get("premium-warning", true); - if (playerName.equals(forPlayer.getUsername()) && premiumWarning - && !core.getPendingConfirms().contains(forPlayer.getUniqueId())) { - String message = core.getMessage("premium-warning"); - forPlayer.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(message)); - core.getPendingConfirms().add(forPlayer.getUniqueId()); - return; - } - - core.getPendingConfirms().remove(forPlayer.getUniqueId()); Runnable task = new AsyncToggleMessage(core, forPlayer, playerName, true, isSourceInvoker); plugin.getScheduler().runAsync(task); } else { diff --git a/velocity/src/main/java/com/github/games647/fastlogin/velocity/task/FloodgateAuthTask.java b/velocity/src/main/java/com/github/games647/fastlogin/velocity/task/FloodgateAuthTask.java index b64bfae69..33ed1fea1 100644 --- a/velocity/src/main/java/com/github/games647/fastlogin/velocity/task/FloodgateAuthTask.java +++ b/velocity/src/main/java/com/github/games647/fastlogin/velocity/task/FloodgateAuthTask.java @@ -55,8 +55,8 @@ protected void startLogin() { core.getPlugin().getSession().put(player.getRemoteAddress(), session); // enable auto login based on the value of 'autoLoginFloodgate' in config.yml - boolean forcedOnlineMode = autoLoginFloodgate.equals("true") - || (autoLoginFloodgate.equals("linked") && isLinked); + boolean forcedOnlineMode = "true".equals(autoLoginFloodgate) + || ("linked".equals(autoLoginFloodgate) && isLinked); // delay sending force command, because Paper will process the login event asynchronously // In this case it means that the force command (plugin message) is already received and processed while