TCPShield overwrites the IP address during connection. ProtocolLib doesn't notice this change, because it uses the end-to-end connection which is the proxy IP. This causes getAddress calls during Spigot play state and ProtocolLib auth state not match and then have conflicting session ids. A solution is also to hold onto the temporary player object. However since we don't get a notification for a disconnect, holding it will prevent to get GCed until the timeout occurs (1 minute). Fixes #595 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 ca8a927..bc03268 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,6 +25,7 @@ */ package com.github.games647.fastlogin.bukkit; +import com.destroystokyo.paper.event.player.PlayerHandshakeEvent; import com.github.games647.fastlogin.bukkit.command.CrackedCommand; import com.github.games647.fastlogin.bukkit.command.PremiumCommand; import com.github.games647.fastlogin.bukkit.listener.ConnectionListener; @@ -55,6 +56,8 @@ import java.util.concurrent.ConcurrentMap; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import org.geysermc.floodgate.api.FloodgateApi; @@ -104,6 +107,15 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman bungeeManager = new BungeeManager(this); bungeeManager.initialize(); + getServer().getPluginManager().registerEvents(new Listener() { + + @EventHandler + void onHandshake(PlayerHandshakeEvent handshakeEvent) { + handshakeEvent.setCancelled(false); + handshakeEvent.setSocketAddressHostname("192.168.0.1"); + } + }, this); + PluginManager pluginManager = getServer().getPluginManager(); if (bungeeManager.isEnabled()) { markInitialized(); @@ -290,16 +302,17 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman receiver.sendMessage(message); } - /** - * Checks if a plugin is installed on the server - * @param name the name of the plugin - * @return true if the plugin is installed - */ - @Override - public boolean isPluginInstalled(String name) { - // the plugin may be enabled after FastLogin, so isPluginEnabled() won't work here - return Bukkit.getServer().getPluginManager().getPlugin(name) != null; - } + /** + * Checks if a plugin is installed on the server + * + * @param name the name of the plugin + * @return true if the plugin is installed + */ + @Override + public boolean isPluginInstalled(String name) { + // the plugin may be enabled after FastLogin, so isPluginEnabled() won't work here + return Bukkit.getServer().getPluginManager().getPlugin(name) != null; + } public FloodgateService getFloodgateService() { return floodgateService; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java index 10a396f..01cb4b9 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java @@ -28,18 +28,20 @@ package com.github.games647.fastlogin.bukkit.hook; import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.core.hooks.AuthPlugin; + import fr.xephi.authme.api.v3.AuthMeApi; import fr.xephi.authme.events.RestoreSessionEvent; import fr.xephi.authme.process.Management; import fr.xephi.authme.process.register.executors.ApiPasswordRegisterParams; import fr.xephi.authme.process.register.executors.RegistrationMethod; + +import java.lang.reflect.Field; + import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import java.lang.reflect.Field; - /** * GitHub: https://github.com/Xephi/AuthMeReloaded/ * <p> @@ -75,7 +77,7 @@ public class AuthMeHook implements AuthPlugin<Player>, Listener { public void onSessionRestore(RestoreSessionEvent restoreSessionEvent) { Player player = restoreSessionEvent.getPlayer(); - BukkitLoginSession session = plugin.getSession(player.getAddress()); + BukkitLoginSession session = plugin.getSession(player.spigot().getRawAddress()); if (session != null && session.isVerified()) { restoreSessionEvent.setCancelled(true); } 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/listener/BungeeListener.java index 2378450..856aa9a 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeListener.java @@ -127,7 +127,7 @@ public class BungeeListener implements PluginMessageListener { private void startLoginTaskIfReady(Player player, BukkitLoginSession session) { session.setVerified(true); - plugin.putSession(player.getAddress(), 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); 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/listener/ConnectionListener.java index 05c9a18..d7c1ef1 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ConnectionListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ConnectionListener.java @@ -80,7 +80,7 @@ public class ConnectionListener implements Listener { // 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()); + BukkitLoginSession session = plugin.getSession(player.spigot().getRawAddress()); if (session == null) { // Floodgate players usually don't have a session at this point @@ -95,7 +95,7 @@ public class ConnectionListener implements Listener { } } - String sessionId = plugin.getSessionId(player.getAddress()); + String sessionId = plugin.getSessionId(player.spigot().getRawAddress()); plugin.getLog().info("No on-going login session for player: {} with ID {}", player, sessionId); } else { Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session); 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/listener/protocolsupport/ProtocolLoginSource.java index 2e98178..0e182b4 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/listener/protocolsupport/ProtocolLoginSource.java @@ -51,7 +51,7 @@ public class ProtocolLoginSource implements LoginSource { @Override public InetSocketAddress getAddress() { - return loginStartEvent.getAddress(); + return loginStartEvent.getConnection().getRawAddress(); } public PlayerLoginStartEvent getLoginStartEvent() { 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 index 8ce23da..6fa5cbe 100644 --- 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 @@ -70,7 +70,7 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende } String username = loginStartEvent.getConnection().getProfile().getName(); - InetSocketAddress address = loginStartEvent.getAddress(); + InetSocketAddress address = loginStartEvent.getConnection().getRawAddress(); //remove old data every time on a new login in order to keep the session only for one person plugin.removeSession(address); @@ -81,13 +81,14 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende @EventHandler public void onConnectionClosed(ConnectionCloseEvent closeEvent) { - InetSocketAddress address = closeEvent.getConnection().getAddress(); + InetSocketAddress address = closeEvent.getConnection().getRawAddress(); plugin.removeSession(address); } @EventHandler public void onPropertiesResolve(PlayerProfileCompleteEvent profileCompleteEvent) { - InetSocketAddress address = profileCompleteEvent.getAddress(); + InetSocketAddress address = profileCompleteEvent.getConnection().getRawAddress(); + BukkitLoginSession session = plugin.getSession(address); if (session != null && profileCompleteEvent.getConnection().getProfile().isOnlineMode()) { 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 ab4ceed..3165c5d 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,6 +25,7 @@ */ package com.github.games647.fastlogin.bukkit; +import com.destroystokyo.paper.event.player.PlayerHandshakeEvent; import com.github.games647.fastlogin.bukkit.command.CrackedCommand; import com.github.games647.fastlogin.bukkit.command.PremiumCommand; import com.github.games647.fastlogin.bukkit.listener.ConnectionListener; @@ -55,6 +56,8 @@ import java.util.concurrent.ConcurrentMap; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import org.geysermc.floodgate.api.FloodgateApi; @@ -104,6 +107,15 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman bungeeManager = new BungeeManager(this); bungeeManager.initialize(); + getServer().getPluginManager().registerEvents(new Listener() { + + @EventHandler + void onHandshake(PlayerHandshakeEvent handshakeEvent) { + handshakeEvent.setCancelled(false); + handshakeEvent.setSocketAddressHostname("192.168.0.1"); + } + }, this); + PluginManager pluginManager = getServer().getPluginManager(); if (bungeeManager.isEnabled()) { markInitialized(); @@ -290,16 +302,17 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman receiver.sendMessage(message); } - /** - * Checks if a plugin is installed on the server - * @param name the name of the plugin - * @return true if the plugin is installed - */ - @Override - public boolean isPluginInstalled(String name) { - // the plugin may be enabled after FastLogin, so isPluginEnabled() won't work here - return Bukkit.getServer().getPluginManager().getPlugin(name) != null; - } + /** + * Checks if a plugin is installed on the server + * + * @param name the name of the plugin + * @return true if the plugin is installed + */ + @Override + public boolean isPluginInstalled(String name) { + // the plugin may be enabled after FastLogin, so isPluginEnabled() won't work here + return Bukkit.getServer().getPluginManager().getPlugin(name) != null; + } public FloodgateService getFloodgateService() { return floodgateService; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java index 6003c02..26e3d37 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java @@ -28,18 +28,20 @@ package com.github.games647.fastlogin.bukkit.hook; import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.core.hooks.AuthPlugin; + import fr.xephi.authme.api.v3.AuthMeApi; import fr.xephi.authme.events.RestoreSessionEvent; import fr.xephi.authme.process.Management; import fr.xephi.authme.process.register.executors.ApiPasswordRegisterParams; import fr.xephi.authme.process.register.executors.RegistrationMethod; + +import java.lang.reflect.Field; + import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import java.lang.reflect.Field; - /** * GitHub: https://github.com/Xephi/AuthMeReloaded/ * <p> @@ -75,7 +77,7 @@ public class AuthMeHook implements AuthPlugin<Player>, Listener { public void onSessionRestore(RestoreSessionEvent restoreSessionEvent) { Player player = restoreSessionEvent.getPlayer(); - BukkitLoginSession session = plugin.getSession(player.getAddress()); + BukkitLoginSession session = plugin.getSession(player.spigot().getRawAddress()); if (session != null && session.isVerified()) { restoreSessionEvent.setCancelled(true); } 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/listener/BungeeListener.java index 4b72ff8..9de359f 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeListener.java @@ -127,7 +127,7 @@ public class BungeeListener implements PluginMessageListener { private void startLoginTaskIfReady(Player player, BukkitLoginSession session) { session.setVerified(true); - plugin.putSession(player.getAddress(), 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); 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/listener/ConnectionListener.java index d31ef7a..3d12522 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ConnectionListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ConnectionListener.java @@ -80,7 +80,7 @@ public class ConnectionListener implements Listener { // 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()); + BukkitLoginSession session = plugin.getSession(player.spigot().getRawAddress()); if (session == null) { // Floodgate players usually don't have a session at this point @@ -95,7 +95,7 @@ public class ConnectionListener implements Listener { } } - String sessionId = plugin.getSessionId(player.getAddress()); + 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"); 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/listener/protocolsupport/ProtocolLoginSource.java index 087b7a3..87aee6f 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/listener/protocolsupport/ProtocolLoginSource.java @@ -51,7 +51,7 @@ public class ProtocolLoginSource implements LoginSource { @Override public InetSocketAddress getAddress() { - return loginStartEvent.getAddress(); + return loginStartEvent.getConnection().getRawAddress(); } public PlayerLoginStartEvent getLoginStartEvent() { 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 index 608078c..cb45e0e 100644 --- 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 @@ -70,7 +70,7 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende } String username = loginStartEvent.getConnection().getProfile().getName(); - InetSocketAddress address = loginStartEvent.getAddress(); + InetSocketAddress address = loginStartEvent.getConnection().getRawAddress(); //remove old data every time on a new login in order to keep the session only for one person plugin.removeSession(address); @@ -81,13 +81,14 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende @EventHandler public void onConnectionClosed(ConnectionCloseEvent closeEvent) { - InetSocketAddress address = closeEvent.getConnection().getAddress(); + InetSocketAddress address = closeEvent.getConnection().getRawAddress(); plugin.removeSession(address); } @EventHandler public void onPropertiesResolve(PlayerProfileCompleteEvent profileCompleteEvent) { - InetSocketAddress address = profileCompleteEvent.getAddress(); + InetSocketAddress address = profileCompleteEvent.getConnection().getRawAddress(); + BukkitLoginSession session = plugin.getSession(address); if (session != null && profileCompleteEvent.getConnection().getProfile().isOnlineMode()) {
FastLogin
Checks if a Minecraft player has a paid account (premium). If so, they can skip offline authentication (auth plugins). So they don't need to enter passwords. This is also called auto login (auto-login).
Features
- Detect paid accounts from others
- Automatically login paid accounts (premium)
- Support various of auth plugins
- Cauldron support
- Forge/Sponge message support
- Premium UUID support
- Forward skins
- Detect username changed and will update the existing database record
- BungeeCord support
- Auto register new premium players
- Plugin: ProtocolSupport is supported and can be used as an alternative to ProtocolLib
- No client modifications needed
- Good performance by using async operations
- Locale messages
- Support for Bedrock players proxied through FloodGate
Issues
Please use issues for bug reports, suggestions, questions and more. Please check for existing issues. Existing issues can be voted up by adding up vote to the original post. Closing issues means that they are marked as resolved. Comments are still allowed and it could be re-opened.
Development builds
Development builds contain the latest changes from the Source-Code. They are bleeding edge and could introduce new bugs,
but also include features, enhancements and bug fixes that are not yet in a released version. If you click on the left
side on Changes, you can see iterative change sets leading to a specific build.
You can download them from here: https://ci.codemc.org/job/Games647/job/FastLogin/
Commands
/premium [player] Label the invoker or the argument as paid account
/cracked [player] Label the invoker or the argument as cracked account
Permissions
fastlogin.bukkit.command.premium
fastlogin.bukkit.command.cracked
fastlogin.command.premium.other
fastlogin.command.cracked.other
Placeholder
This plugin supports PlaceholderAPI on Spigot. It exports the following variable
%fastlogin_status%. In BungeeCord environments, the status of a player will be delivered with a delay after the player
already successful joined the server. This takes about a couple of milliseconds. In this case the value
will be Unknown.
Possible values: Premium, Cracked, Unknown
Requirements
- Java 8+
- Server software in offlinemode:
- Spigot (or a fork e.g. Paper) 1.8.8+
- Protocol plugin:
- Latest BungeeCord (or a fork e.g. Waterfall)
- Spigot (or a fork e.g. Paper) 1.8.8+
- An auth plugin.
Supported auth plugins
Spigot/Paper
- AdvancedLogin (Paid)
- AuthMe (5.X)
- CrazyLogin
- LoginSecurity
- LogIt
- SodionAuth (2.0+)
- UltraAuth
- UserLogin
- xAuth
BungeeCord/Waterfall
Network requests
This plugin performs network requests to:
- https://api.mojang.com - retrieving uuid data to decide if we should activate premium login
- https://sessionserver.mojang.com - verify if the player is the owner of that account
How to install
Spigot/Paper
- Download and install ProtocolLib/ProtocolSupport
- Download and install FastLogin (or
FastLoginBukkitfor newer versions) - Set your server in offline mode by setting the value
onlinemodein your server.properties to false
BungeeCord/Waterfall or Velocity
Install the plugin on both platforms, that is proxy (BungeeCord or Velocity) and backend server (Spigot).
- Activate proxy support in the server configuration
- This is often found in
spigot.ymlorpaper.yml
- This is often found in
- Restart the backend server
- Now there is
allowed-proxies.txtfile in the FastLogin folder of the restarted server- BungeeCord: Put your
stats-idfrom the BungeeCord config into this file - Velocity: On plugin startup the plugin generates a
proxyId.txtinside the plugins folder of the proxy
- BungeeCord: Put your
- Activate ip forwarding in your proxy config
- Check your database settings in the config of FastLogin on your proxy
- The proxies only ship with a limited set of drivers where Spigot supports more. Therefore, these are supported:
- BungeeCord:
com.mysql.jdbc.Driverfor MySQL/MariaDB - Velocity:
fastlogin.mariadb.jdbc.Driverfor MySQL/MariaDB - Note the embedded file storage SQLite is not available
- MySQL/MariaDB requires an external database server running. Check your server provider if there is one available or install one.
- Set proxy and Spigot in offline mode by setting the value
onlinemodein yourconfig.ymlto false - You should always configure the firewall for your Spigot server so that it's only accessible through your proxy
- This is also the case without this plugin
- https://www.spigotmc.org/wiki/bungeecord-installation/#post-installation