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 ebfa1443..6d106b35 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 @@ -35,6 +35,7 @@ import com.github.games647.fastlogin.bukkit.listener.protocolsupport.ProtocolSup import com.github.games647.fastlogin.bukkit.task.DelayedAuthHook; import com.github.games647.fastlogin.core.CommonUtil; import com.github.games647.fastlogin.core.PremiumStatus; +import com.github.games647.fastlogin.core.hooks.FloodgateService; import com.github.games647.fastlogin.core.shared.FastLoginCore; import com.github.games647.fastlogin.core.shared.PlatformPlugin; @@ -42,7 +43,6 @@ import io.papermc.lib.PaperLib; import java.net.InetSocketAddress; import java.nio.file.Path; -import java.util.Locale; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -69,6 +69,7 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin core; + private FloodgateService floodgateService; private PremiumPlaceholder premiumPlaceholder; @@ -88,13 +89,10 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin - * Writes to Log if the value is invalid. - *

- * This should be used for: - *

- *

- * - * @param key the key of the entry in config.yml - * @return true if the entry's value is "true", "false", or "linked" - */ - private boolean isValidFloodgateConfigString(String key) { - String value = core.getConfig().get(key).toString().toLowerCase(Locale.ENGLISH); - if (!value.equals("true") && !value.equals("linked") && !value.equals("false") && !value.equals("no-conflict")) { - logger.error("Invalid value detected for {} in FastLogin/config.yml.", key); - return false; - } - return true; - } - /** * Checks if a plugin is installed on the server * @param name the name of the plugin @@ -286,6 +274,11 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin { - // 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.getAddress()); - - boolean isFloodgateLogin = false; - if (Bukkit.getServer().getPluginManager().isPluginEnabled("floodgate")) { - FloodgatePlayer floodgatePlayer = FloodgateApi.getInstance().getPlayer(player.getUniqueId()); - if (floodgatePlayer != null) { - isFloodgateLogin = true; - Runnable floodgateAuthTask = new FloodgateAuthTask(plugin.getCore(), player, floodgatePlayer); - Bukkit.getScheduler().runTaskAsynchronously(plugin, floodgateAuthTask); - } - } - - if (!isFloodgateLogin) { - if (session == null) { - String sessionId = plugin.getSessionId(player.getAddress()); - plugin.getLog().info("No on-going login session for player: {} with ID {}", player, sessionId); - } else { - Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session); - Bukkit.getScheduler().runTaskAsynchronously(plugin, forceLoginTask); - } - } - - plugin.getBungeeManager().markJoinEventFired(player); + 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.getAddress()); + FloodgateService floodgateService = plugin.getFloodgateService(); + if (floodgateService != null) { + FloodgatePlayer floodgatePlayer = floodgateService.getFloodgatePlayer(player.getUniqueId()); + if (floodgatePlayer != null) { + Runnable floodgateAuthTask = new FloodgateAuthTask(plugin.getCore(), player, floodgatePlayer); + Bukkit.getScheduler().runTaskAsynchronously(plugin, floodgateAuthTask); + return; + } + } + + if (session == null) { + String sessionId = plugin.getSessionId(player.getAddress()); + plugin.getLog().info("No on-going login session for player: {} with ID {}", player, sessionId); + } else { + 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(); 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/listener/protocollib/NameCheckTask.java index 54d2ea3e..589057a8 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/listener/protocollib/NameCheckTask.java @@ -54,7 +54,7 @@ public class NameCheckTask extends JoinManagement { +public class FloodgateService { - private final FastLoginCore core; + private final FastLoginCore core; - public FloodgateHook(FastLoginCore core) { + public FloodgateService(FastLoginCore core) { this.core = core; } + /** + * Checks if a config entry (related to Floodgate) is valid.
+ * Writes to Log if the value is invalid. + *

+ * This should be used for: + *

    + *
  • allowFloodgateNameConflict + *
  • autoLoginFloodgate + *
  • autoRegisterFloodgate + *
+ *

+ * + * @param key the key of the entry in config.yml + * @return true if the entry's value is "true", "false", or "linked" + */ + public boolean isValidFloodgateConfigString(String key) { + String value = core.getConfig().get(key).toString().toLowerCase(Locale.ENGLISH); + if (!value.equals("true") && !value.equals("linked") && !value.equals("false") && !value.equals("no-conflict")) { + core.getPlugin().getLog().error("Invalid value detected for {} in FastLogin/config.yml.", key); + return false; + } + + return true; + } + + public boolean isUsernameForbidden(StoredProfile profile) { + String playerPrefix = FloodgateApi.getInstance().getPlayerPrefix(); + return profile.getName().startsWith(playerPrefix) && !playerPrefix.isEmpty(); + } + /** * Check if the player's name conflicts an existing Java player's name, and * kick them if it does @@ -55,10 +88,10 @@ public class FloodgateHook

{ String allowConflict = core.getConfig().get("allowFloodgateNameConflict").toString().toLowerCase(); // check if the Bedrock player is linked to a Java account - boolean isLinked = ((FloodgatePlayer) floodgatePlayer).getLinkedPlayer() != null; + boolean isLinked = floodgatePlayer.getLinkedPlayer() != null; - if (allowConflict.equals("false") - || allowConflict.equals("linked") && !isLinked) { + if ("false".equals(allowConflict) + || "linked".equals(allowConflict) && !isLinked) { // check for conflicting Premium Java name Optional premiumUUID = Optional.empty(); @@ -66,13 +99,13 @@ public class FloodgateHook

{ premiumUUID = core.getResolver().findProfile(username); } catch (IOException | RateLimitException e) { core.getPlugin().getLog().error( - "Could not check wether Floodgate Player {}'s name conflicts a premium Java player's name.", + "Could not check whether Floodgate Player {}'s name conflicts a premium Java player's name.", username); try { source.kick("Could not check if your name conflicts an existing premium Java account's name.\n" + "This is usually a serverside error."); - } catch (Exception e1) { - core.getPlugin().getLog().error("Could not kick Player {}", username); + } catch (Exception ex) { + core.getPlugin().getLog().error("Could not kick Player {}", username, ex); } } @@ -81,8 +114,8 @@ public class FloodgateHook

{ username); try { source.kick("Your name conflicts an existing premium Java account's name"); - } catch (Exception e) { - core.getPlugin().getLog().error("Could not kick Player {}", username); + } catch (Exception ex) { + core.getPlugin().getLog().error("Could not kick Player {}", username, ex); } } } else { @@ -99,14 +132,25 @@ public class FloodgateHook

{ * @return FloodgatePlayer if found, null otherwise */ public FloodgatePlayer getFloodgatePlayer(String username) { - if (core.getPlugin().isPluginInstalled("floodgate")) { - for (FloodgatePlayer floodgatePlayer : FloodgateApi.getInstance().getPlayers()) { - if (floodgatePlayer.getUsername().equals(username)) { - return floodgatePlayer; - } + for (FloodgatePlayer floodgatePlayer : FloodgateApi.getInstance().getPlayers()) { + if (floodgatePlayer.getUsername().equals(username)) { + return floodgatePlayer; } } return null; } + + public FloodgatePlayer getFloodgatePlayer(UUID uuid) { + return FloodgateApi.getInstance().getPlayer(uuid); + } + + public boolean isFloodgatePlayer(UUID uuid) { + return getFloodgatePlayer(uuid) != null; + } + + public boolean isFloodgateConnection(String username) { + return getFloodgatePlayer(username) != 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 27ef947b..22b7bec4 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 @@ -27,13 +27,13 @@ package com.github.games647.fastlogin.core.shared; import com.github.games647.craftapi.resolver.MojangResolver; import com.github.games647.craftapi.resolver.http.RotatingProxySelector; -import com.github.games647.fastlogin.core.storage.MySQLStorage; -import com.github.games647.fastlogin.core.storage.SQLStorage; import com.github.games647.fastlogin.core.CommonUtil; import com.github.games647.fastlogin.core.RateLimiter; import com.github.games647.fastlogin.core.hooks.AuthPlugin; import com.github.games647.fastlogin.core.hooks.DefaultPasswordGenerator; import com.github.games647.fastlogin.core.hooks.PasswordGenerator; +import com.github.games647.fastlogin.core.storage.MySQLStorage; +import com.github.games647.fastlogin.core.storage.SQLStorage; import com.github.games647.fastlogin.core.storage.SQLiteStorage; import com.google.common.net.HostAndPort; import com.zaxxer.hikari.HikariConfig; 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 e10b2d09..25a0dc44 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 @@ -29,26 +29,25 @@ import com.github.games647.craftapi.model.Profile; import com.github.games647.craftapi.resolver.RateLimitException; import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.hooks.AuthPlugin; -import com.github.games647.fastlogin.core.hooks.FloodgateHook; +import com.github.games647.fastlogin.core.hooks.FloodgateService; import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent; import java.util.Optional; -import org.geysermc.floodgate.api.FloodgateApi; -import org.geysermc.floodgate.api.player.FloodgatePlayer; - import net.md_5.bungee.config.Configuration; +import org.geysermc.floodgate.api.player.FloodgatePlayer; + public abstract class JoinManagement

{ protected final FastLoginCore core; protected final AuthPlugin

authHook; - private final FloodgateHook floodgateHook; + private final FloodgateService floodgateService; - public JoinManagement(FastLoginCore core, AuthPlugin

authHook) { + public JoinManagement(FastLoginCore core, AuthPlugin

authHook, FloodgateService floodService) { this.core = core; this.authHook = authHook; - this.floodgateHook = new FloodgateHook<>(core); + this.floodgateService = floodService; } public void onLogin(String username, S source) { @@ -59,12 +58,14 @@ public abstract class JoinManagement

{ } //check if the player is connecting through Floodgate - FloodgatePlayer floodgatePlayer = floodgateHook.getFloodgatePlayer(username); - - if (floodgatePlayer != null) { - floodgateHook.checkFloodgateNameConflict(username, source, floodgatePlayer); - return; + if (floodgateService != null) { + if (floodgateService.isFloodgateConnection(username)) { + floodgateService.checkFloodgateNameConflict(username, source, floodgatePlayer); + // skip flow for any floodgate player + return; + } } + callFastLoginPreLoginEvent(username, source, profile); Configuration config = core.getConfig(); @@ -77,12 +78,9 @@ public abstract class JoinManagement

{ core.getPlugin().getLog().info("Requesting premium login for registered player: {}", username); requestPremiumLogin(source, profile, username, true); } else { - if (profile.getName().startsWith(FloodgateApi.getInstance().getPlayerPrefix())&&!FloodgateApi.getInstance().getPlayerPrefix().isEmpty()) { - core.getPlugin().getLog().info("Floodgate Prefix detected on cracked player"); - source.kick("Your username contains illegal characters"); - return; + if (isValidUsername(source, profile)) { + startCrackedSession(source, profile, username); } - startCrackedSession(source, profile, username); } } else { if (core.getPendingLogin().remove(ip + username) != null && config.get("secondAttemptCracked", false)) { @@ -120,6 +118,16 @@ public abstract class JoinManagement

{ } } + protected boolean isValidUsername(LoginSource source, StoredProfile profile) throws Exception { + if (floodgateService != null && floodgateService.isUsernameForbidden(profile)) { + core.getPlugin().getLog().info("Floodgate Prefix detected on cracked player"); + source.kick("Your username contains illegal characters"); + return false; + } + + return true; + } + private boolean checkPremiumName(S source, String username, StoredProfile profile) throws Exception { core.getPlugin().getLog().info("GameProfile {} uses a premium username", username); if (core.getConfig().get("autoRegister", false) && (authHook == null || !authHook.isRegistered(username))) { 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 11971e45..aba983a3 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 @@ -26,6 +26,7 @@ package com.github.games647.fastlogin.core.shared; import com.github.games647.fastlogin.core.AsyncScheduler; +import com.github.games647.fastlogin.core.hooks.FloodgateService; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.nio.file.Path; @@ -53,6 +54,8 @@ public interface PlatformPlugin { } } + FloodgateService getFloodgateService(); + default ThreadFactory getThreadFactory() { return new ThreadFactoryBuilder() .setNameFormat(getName() + " Pool Thread #%1$d")