mirror of
https://github.com/TuxCoding/FastLogin.git
synced 2025-08-02 20:24:41 +02:00
Fix TCPShield compat by using raw address for sessions
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
This commit is contained in:
@@ -145,7 +145,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.destroystokyo.paper</groupId>
|
<groupId>com.destroystokyo.paper</groupId>
|
||||||
<artifactId>paper-api</artifactId>
|
<artifactId>paper-api</artifactId>
|
||||||
<version>1.15.2-R0.1-SNAPSHOT</version>
|
<version>1.16.5-R0.1-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.github.games647.fastlogin.bukkit;
|
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.CrackedCommand;
|
||||||
import com.github.games647.fastlogin.bukkit.command.PremiumCommand;
|
import com.github.games647.fastlogin.bukkit.command.PremiumCommand;
|
||||||
import com.github.games647.fastlogin.bukkit.listener.ConnectionListener;
|
import com.github.games647.fastlogin.bukkit.listener.ConnectionListener;
|
||||||
@@ -51,6 +52,8 @@ import java.util.concurrent.ConcurrentMap;
|
|||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.plugin.PluginManager;
|
import org.bukkit.plugin.PluginManager;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -64,10 +67,9 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
|||||||
private final ConcurrentMap<String, BukkitLoginSession> loginSession = CommonUtil.buildCache(1, -1);
|
private final ConcurrentMap<String, BukkitLoginSession> loginSession = CommonUtil.buildCache(1, -1);
|
||||||
private final Map<UUID, PremiumStatus> premiumPlayers = new ConcurrentHashMap<>();
|
private final Map<UUID, PremiumStatus> premiumPlayers = new ConcurrentHashMap<>();
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
|
private final BukkitScheduler scheduler;
|
||||||
private boolean serverStarted;
|
private boolean serverStarted;
|
||||||
private BungeeManager bungeeManager;
|
private BungeeManager bungeeManager;
|
||||||
private final BukkitScheduler scheduler;
|
|
||||||
private FastLoginCore<Player, CommandSender, FastLoginBukkit> core;
|
private FastLoginCore<Player, CommandSender, FastLoginBukkit> core;
|
||||||
|
|
||||||
private PremiumPlaceholder premiumPlaceholder;
|
private PremiumPlaceholder premiumPlaceholder;
|
||||||
@@ -88,17 +90,26 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
|||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check Floodgate config values
|
// Check Floodgate config values
|
||||||
if (!isValidFloodgateConfigString("autoLoginFloodgate")
|
if (!isValidFloodgateConfigString("autoLoginFloodgate")
|
||||||
|| !isValidFloodgateConfigString("allowFloodgateNameConflict")) {
|
|| !isValidFloodgateConfigString("allowFloodgateNameConflict")) {
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bungeeManager = new BungeeManager(this);
|
bungeeManager = new BungeeManager(this);
|
||||||
bungeeManager.initialize();
|
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();
|
PluginManager pluginManager = getServer().getPluginManager();
|
||||||
if (bungeeManager.isEnabled()) {
|
if (bungeeManager.isEnabled()) {
|
||||||
markInitialized();
|
markInitialized();
|
||||||
@@ -182,10 +193,6 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
|||||||
public BukkitLoginSession getSession(InetSocketAddress addr) {
|
public BukkitLoginSession getSession(InetSocketAddress addr) {
|
||||||
String id = getSessionId(addr);
|
String id = getSessionId(addr);
|
||||||
BukkitLoginSession session = loginSession.get(id);
|
BukkitLoginSession session = loginSession.get(id);
|
||||||
if (session == null) {
|
|
||||||
logger.info("No session found for id {}", id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +202,6 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
|||||||
|
|
||||||
public void putSession(InetSocketAddress addr, BukkitLoginSession session) {
|
public void putSession(InetSocketAddress addr, BukkitLoginSession session) {
|
||||||
String id = getSessionId(addr);
|
String id = getSessionId(addr);
|
||||||
logger.info("Starting session {}", id);
|
|
||||||
loginSession.put(id, session);
|
loginSession.put(id, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,44 +262,45 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
|||||||
public void sendMessage(CommandSender receiver, String message) {
|
public void sendMessage(CommandSender receiver, String message) {
|
||||||
receiver.sendMessage(message);
|
receiver.sendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a config entry (related to Floodgate) is valid. <br>
|
|
||||||
* Writes to Log if the value is invalid.
|
|
||||||
* <p>
|
|
||||||
* This should be used for:
|
|
||||||
* <ul>
|
|
||||||
* <li>allowFloodgateNameConflict
|
|
||||||
* <li>autoLoginFloodgate
|
|
||||||
* <li>autoRegisterFloodgate
|
|
||||||
* </ul>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param key the key of the entry in config.yml
|
|
||||||
* @return <b>true</b> 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
|
|
||||||
* @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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send warning messages to log if incompatible plugins are used
|
* Checks if a config entry (related to Floodgate) is valid. <br>
|
||||||
|
* Writes to Log if the value is invalid.
|
||||||
|
* <p>
|
||||||
|
* This should be used for:
|
||||||
|
* <ul>
|
||||||
|
* <li>allowFloodgateNameConflict
|
||||||
|
* <li>autoLoginFloodgate
|
||||||
|
* <li>autoRegisterFloodgate
|
||||||
|
* </ul>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param key the key of the entry in config.yml
|
||||||
|
* @return <b>true</b> 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
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send warning messages to log if incompatible plugins are used
|
||||||
*/
|
*/
|
||||||
private void dependencyWarnings() {
|
private void dependencyWarnings() {
|
||||||
if (isPluginInstalled("floodgate-bukkit")) {
|
if (isPluginInstalled("floodgate-bukkit")) {
|
||||||
@@ -303,13 +310,13 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
|||||||
+ "Floodgate 2.0 from https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/dev%252F2.0/");
|
+ "Floodgate 2.0 from https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/dev%252F2.0/");
|
||||||
logger.warn("Don't forget to update Geyser to a supported version as well from "
|
logger.warn("Don't forget to update Geyser to a supported version as well from "
|
||||||
+ "https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/floodgate-2.0/");
|
+ "https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/floodgate-2.0/");
|
||||||
} else if (isPluginInstalled("floodgate") && isPluginInstalled("ProtocolLib")) {
|
} else if (isPluginInstalled("floodgate") && isPluginInstalled("ProtocolLib")) {
|
||||||
logger.warn("We have detected that you are running FastLogin alongside Floodgate and ProtocolLib.");
|
logger.warn("We have detected that you are running FastLogin alongside Floodgate and ProtocolLib.");
|
||||||
logger.warn("Currently there is an issue with FastLogin that prevents Floodgate's name prefixes from " +
|
logger.warn("Currently there is an issue with FastLogin that prevents Floodgate's name prefixes from " +
|
||||||
"showing up when it is together used with ProtocolLib.");
|
"showing up when it is together used with ProtocolLib.");
|
||||||
logger.warn("If you would like to use Floodgate name prefixes, you can replace ProtocolLib with " +
|
logger.warn("If you would like to use Floodgate name prefixes, you can replace ProtocolLib with " +
|
||||||
"ProtocolSupport which does not have this issue.");
|
"ProtocolSupport which does not have this issue.");
|
||||||
logger.warn("For more information visit https://github.com/games647/FastLogin/issues/493");
|
logger.warn("For more information visit https://github.com/games647/FastLogin/issues/493");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,18 +28,20 @@ package com.github.games647.fastlogin.bukkit.hook;
|
|||||||
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
|
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
|
||||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||||
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
|
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
|
||||||
|
|
||||||
import fr.xephi.authme.api.v3.AuthMeApi;
|
import fr.xephi.authme.api.v3.AuthMeApi;
|
||||||
import fr.xephi.authme.events.RestoreSessionEvent;
|
import fr.xephi.authme.events.RestoreSessionEvent;
|
||||||
import fr.xephi.authme.process.Management;
|
import fr.xephi.authme.process.Management;
|
||||||
import fr.xephi.authme.process.register.executors.ApiPasswordRegisterParams;
|
import fr.xephi.authme.process.register.executors.ApiPasswordRegisterParams;
|
||||||
import fr.xephi.authme.process.register.executors.RegistrationMethod;
|
import fr.xephi.authme.process.register.executors.RegistrationMethod;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GitHub: https://github.com/Xephi/AuthMeReloaded/
|
* GitHub: https://github.com/Xephi/AuthMeReloaded/
|
||||||
* <p>
|
* <p>
|
||||||
@@ -75,7 +77,7 @@ public class AuthMeHook implements AuthPlugin<Player>, Listener {
|
|||||||
public void onSessionRestore(RestoreSessionEvent restoreSessionEvent) {
|
public void onSessionRestore(RestoreSessionEvent restoreSessionEvent) {
|
||||||
Player player = restoreSessionEvent.getPlayer();
|
Player player = restoreSessionEvent.getPlayer();
|
||||||
|
|
||||||
BukkitLoginSession session = plugin.getSession(player.getAddress());
|
BukkitLoginSession session = plugin.getSession(player.spigot().getRawAddress());
|
||||||
if (session != null && session.isVerified()) {
|
if (session != null && session.isVerified()) {
|
||||||
restoreSessionEvent.setCancelled(true);
|
restoreSessionEvent.setCancelled(true);
|
||||||
}
|
}
|
||||||
|
@@ -126,7 +126,7 @@ public class BungeeListener implements PluginMessageListener {
|
|||||||
|
|
||||||
private void startLoginTaskIfReady(Player player, BukkitLoginSession session) {
|
private void startLoginTaskIfReady(Player player, BukkitLoginSession session) {
|
||||||
session.setVerified(true);
|
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
|
// only start a new login task if the join event fired earlier. This event then didn
|
||||||
boolean result = plugin.getBungeeManager().didJoinEventFired(player);
|
boolean result = plugin.getBungeeManager().didJoinEventFired(player);
|
||||||
|
@@ -72,7 +72,7 @@ public class ConnectionListener implements Listener {
|
|||||||
// session exists so the player is ready for force login
|
// session exists so the player is ready for force login
|
||||||
// cases: Paper (firing BungeeCord message before PlayerJoinEvent) or not running BungeeCord and already
|
// cases: Paper (firing BungeeCord message before PlayerJoinEvent) or not running BungeeCord and already
|
||||||
// having the login session from the login process
|
// having the login session from the login process
|
||||||
BukkitLoginSession session = plugin.getSession(player.getAddress());
|
BukkitLoginSession session = plugin.getSession(player.spigot().getRawAddress());
|
||||||
|
|
||||||
boolean isFloodgateLogin = false;
|
boolean isFloodgateLogin = false;
|
||||||
if (Bukkit.getServer().getPluginManager().isPluginEnabled("floodgate")) {
|
if (Bukkit.getServer().getPluginManager().isPluginEnabled("floodgate")) {
|
||||||
@@ -86,7 +86,7 @@ public class ConnectionListener implements Listener {
|
|||||||
|
|
||||||
if (!isFloodgateLogin) {
|
if (!isFloodgateLogin) {
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
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("No on-going login session for player: {} with ID {}", player, sessionId);
|
||||||
} else {
|
} else {
|
||||||
Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);
|
Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);
|
||||||
|
@@ -188,7 +188,7 @@ public class VerifyResponseTask implements Runnable {
|
|||||||
|
|
||||||
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L182
|
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L182
|
||||||
if (!Arrays.equals(requestVerify, EncryptionUtil.decrypt(serverKey.getPrivate(), responseVerify))) {
|
if (!Arrays.equals(requestVerify, EncryptionUtil.decrypt(serverKey.getPrivate(), responseVerify))) {
|
||||||
//check if the verify token are equal to the server sent one
|
//check if the verify-token are equal to the server sent one
|
||||||
disconnect("invalid-verify-token", true
|
disconnect("invalid-verify-token", true
|
||||||
, "GameProfile {0} ({1}) tried to login with an invalid verify token. Server: {2} Client: {3}"
|
, "GameProfile {0} ({1}) tried to login with an invalid verify token. Server: {2} Client: {3}"
|
||||||
, session.getRequestUsername(), packetEvent.getPlayer().getAddress(), requestVerify, responseVerify);
|
, session.getRequestUsername(), packetEvent.getPlayer().getAddress(), requestVerify, responseVerify);
|
||||||
|
@@ -51,7 +51,7 @@ public class ProtocolLoginSource implements LoginSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InetSocketAddress getAddress() {
|
public InetSocketAddress getAddress() {
|
||||||
return loginStartEvent.getAddress();
|
return loginStartEvent.getConnection().getRawAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerLoginStartEvent getLoginStartEvent() {
|
public PlayerLoginStartEvent getLoginStartEvent() {
|
||||||
|
@@ -71,7 +71,7 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
|
|||||||
}
|
}
|
||||||
|
|
||||||
String username = loginStartEvent.getConnection().getProfile().getName();
|
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
|
//remove old data every time on a new login in order to keep the session only for one person
|
||||||
plugin.removeSession(address);
|
plugin.removeSession(address);
|
||||||
@@ -82,13 +82,14 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onConnectionClosed(ConnectionCloseEvent closeEvent) {
|
public void onConnectionClosed(ConnectionCloseEvent closeEvent) {
|
||||||
InetSocketAddress address = closeEvent.getConnection().getAddress();
|
InetSocketAddress address = closeEvent.getConnection().getRawAddress();
|
||||||
plugin.removeSession(address);
|
plugin.removeSession(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPropertiesResolve(PlayerProfileCompleteEvent profileCompleteEvent) {
|
public void onPropertiesResolve(PlayerProfileCompleteEvent profileCompleteEvent) {
|
||||||
InetSocketAddress address = profileCompleteEvent.getAddress();
|
InetSocketAddress address = profileCompleteEvent.getConnection().getRawAddress();
|
||||||
|
|
||||||
BukkitLoginSession session = plugin.getSession(address);
|
BukkitLoginSession session = plugin.getSession(address);
|
||||||
|
|
||||||
if (session != null && profileCompleteEvent.getConnection().getProfile().isOnlineMode()) {
|
if (session != null && profileCompleteEvent.getConnection().getProfile().isOnlineMode()) {
|
||||||
|
Reference in New Issue
Block a user