Compare commits

...

5 Commits

64 changed files with 477 additions and 349 deletions

View File

@ -1,4 +1,5 @@
# Automatically build, run unit and integration tests to detect errors early (CI provided by GitHub) # Automatically build, run unit and integration tests to detect errors early (CI provided by GitHub)
# including making pull requests review easier
# Human readable name in the actions tab # Human readable name in the actions tab
name: Java CI name: Java CI
@ -45,4 +46,4 @@ jobs:
# Run non-interactive, package (with compile+test), # Run non-interactive, package (with compile+test),
# ignore snapshot updates, because they are likely to have breaking changes, enforce checksums to validate # ignore snapshot updates, because they are likely to have breaking changes, enforce checksums to validate
# possible errors in dependencies # possible errors in dependencies
run: mvn test --batch-mode --no-snapshot-updates --strict-checksums --file pom.xml run: mvn package test --batch-mode --no-snapshot-updates --strict-checksums --file pom.xml

View File

@ -0,0 +1,24 @@
package com.github.games647.fastlogin.bukkit;
import com.github.games647.fastlogin.bukkit.auth.BukkitLoginSession;
import com.github.games647.fastlogin.core.SessionManager;
import java.net.InetSocketAddress;
import java.util.UUID;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
public class BukkitSessionManager extends SessionManager<PlayerQuitEvent, InetSocketAddress, BukkitLoginSession>
implements Listener {
@EventHandler
@Override
public void onPlayQuit(PlayerQuitEvent quitEvent) {
Player player = quitEvent.getPlayer();
UUID playerId = player.getUniqueId();
endPlaySession(playerId);
}
}

View File

@ -1,45 +1,46 @@
package com.github.games647.fastlogin.bukkit; package com.github.games647.fastlogin.bukkit;
import com.github.games647.fastlogin.bukkit.auth.proxy.ProxyManager;
import com.github.games647.fastlogin.bukkit.auth.protocollib.ProtocolLibListener;
import com.github.games647.fastlogin.bukkit.auth.protocolsupport.ProtocolSupportListener;
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.hook.DelayedAuthHook;
import com.github.games647.fastlogin.bukkit.listener.ConnectionListener; import com.github.games647.fastlogin.bukkit.listener.ConnectionListener;
import com.github.games647.fastlogin.bukkit.listener.PaperPreLoginListener; import com.github.games647.fastlogin.bukkit.listener.PaperPreLoginListener;
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.core.CommonUtil; import com.github.games647.fastlogin.core.CommonUtil;
import com.github.games647.fastlogin.core.PremiumStatus; import com.github.games647.fastlogin.core.PremiumStatus;
import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.FastLoginCore; import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.PlatformPlugin; import com.github.games647.fastlogin.core.shared.PlatformPlugin;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import java.nio.file.Path;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
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;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/** /**
* This plugin checks if a player has a paid account and if so tries to skip offline mode authentication. * This plugin checks if a player has a paid account and if so tries to skip offline mode authentication.
*/ */
public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<CommandSender> { public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<CommandSender> {
//1 minutes should be enough as a timeout for bad internet connection (Server, Client and Mojang) private final BukkitSessionManager sessionManager = new BukkitSessionManager();
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 FastLoginCore<Player, CommandSender, FastLoginBukkit> core = new FastLoginCore<>(this);
private boolean serverStarted; private final Logger logger;
private BungeeManager bungeeManager;
private final BukkitScheduler scheduler; private final BukkitScheduler scheduler;
private FastLoginCore<Player, CommandSender, FastLoginBukkit> core;
private ProxyManager proxyManager;
private PremiumPlaceholder premiumPlaceholder; private PremiumPlaceholder premiumPlaceholder;
@ -50,7 +51,6 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
@Override @Override
public void onEnable() { public void onEnable() {
core = new FastLoginCore<>(this);
core.load(); core.load();
if (getServer().getOnlineMode()) { if (getServer().getOnlineMode()) {
@ -60,13 +60,11 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
return; return;
} }
bungeeManager = new BungeeManager(this); proxyManager = new ProxyManager(this);
bungeeManager.initialize(); proxyManager.initialize();
PluginManager pluginManager = getServer().getPluginManager(); PluginManager pluginManager = getServer().getPluginManager();
if (bungeeManager.isEnabled()) { if (!proxyManager.isEnabled()) {
markInitialized();
} else {
if (!core.setupDatabase()) { if (!core.setupDatabase()) {
setEnabled(false); setEnabled(false);
return; return;
@ -76,13 +74,8 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
pluginManager.registerEvents(new ProtocolSupportListener(this, core.getRateLimiter()), this); pluginManager.registerEvents(new ProtocolSupportListener(this, core.getRateLimiter()), this);
} else if (pluginManager.isPluginEnabled("ProtocolLib")) { } else if (pluginManager.isPluginEnabled("ProtocolLib")) {
ProtocolLibListener.register(this, core.getRateLimiter()); ProtocolLibListener.register(this, core.getRateLimiter());
//if server is using paper - we need to set the skin at pre login anyway, so no need for this listener
if (!PaperLib.isPaper() && getConfig().getBoolean("forwardSkin")) {
pluginManager.registerEvents(new SkinApplyListener(this), this);
}
} else { } else {
logger.warn("Either ProtocolLib or ProtocolSupport have to be installed if you don't use BungeeCord"); logger.warn("Either ProtocolLib or ProtocolSupport have to be installed if you don't use proxies");
} }
} }
@ -108,14 +101,10 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
@Override @Override
public void onDisable() { public void onDisable() {
loginSession.clear();
premiumPlayers.clear(); premiumPlayers.clear();
if (core != null) {
core.close(); core.close();
}
bungeeManager.cleanup(); proxyManager.cleanup();
if (getServer().getPluginManager().isPluginEnabled("PlaceholderAPI") && premiumPlaceholder != null) { if (getServer().getPluginManager().isPluginEnabled("PlaceholderAPI") && premiumPlaceholder != null) {
premiumPlaceholder.unregister(); premiumPlaceholder.unregister();
} }
@ -125,66 +114,40 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
return core; return core;
} }
/**
* Fetches the premium status of an online player.
*
* @param onlinePlayer
* @return the online status or unknown if an error happened, the player isn't online or a proxy doesn't send
* us the status message yet (This means you cannot check the login status on the PlayerJoinEvent).
* @deprecated this method could be removed in future versions and exists only as a temporarily solution
*/
@Deprecated
public PremiumStatus getStatus(UUID onlinePlayer) {
StoredProfile playSession = sessionManager.getPlaySession(onlinePlayer);
return Optional.ofNullable(playSession).map(profile -> {
if (profile.isPremium())
return PremiumStatus.PREMIUM;
return PremiumStatus.CRACKED;
}).orElse(PremiumStatus.UNKNOWN);
}
/** /**
* Gets a thread-safe map about players which are connecting to the server are being checked to be premium (paid * Gets a thread-safe map about players which are connecting to the server are being checked to be premium (paid
* account) * account)
* *
* @return a thread-safe loginSession map * @return a thread-safe loginSession map
*/ */
public ConcurrentMap<String, BukkitLoginSession> getLoginSessions() { public BukkitSessionManager getSessionManager() {
return loginSession; return sessionManager;
}
public BukkitLoginSession getSession(InetSocketAddress addr) {
String id = getSessionId(addr);
return loginSession.get(id);
}
public String getSessionId(InetSocketAddress addr) {
return addr.getAddress().getHostAddress() + ':' + addr.getPort();
}
public void putSession(InetSocketAddress addr, BukkitLoginSession session) {
String id = getSessionId(addr);
loginSession.put(id, session);
}
public void removeSession(InetSocketAddress addr) {
String id = getSessionId(addr);
loginSession.remove(id);
} }
public Map<UUID, PremiumStatus> getPremiumPlayers() { public Map<UUID, PremiumStatus> getPremiumPlayers() {
return premiumPlayers; return premiumPlayers;
} }
/** public ProxyManager getProxyManager() {
* Fetches the premium status of an online player. return proxyManager;
*
* @param onlinePlayer
* @return the online status or unknown if an error happened, the player isn't online or BungeeCord doesn't send
* us the status message yet (This means you cannot check the login status on the PlayerJoinEvent).
*/
public PremiumStatus getStatus(UUID onlinePlayer) {
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 @Override

View File

@ -1,14 +1,13 @@
package com.github.games647.fastlogin.bukkit.task; package com.github.games647.fastlogin.bukkit;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.auth.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginAutoLoginEvent; import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginAutoLoginEvent;
import com.github.games647.fastlogin.core.PremiumStatus; import com.github.games647.fastlogin.core.PremiumStatus;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.message.SuccessMessage; import com.github.games647.fastlogin.core.message.SuccessMessage;
import com.github.games647.fastlogin.core.shared.FastLoginCore; import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.ForceLoginManagement; import com.github.games647.fastlogin.core.auth.ForceLoginManagement;
import com.github.games647.fastlogin.core.shared.LoginSession; import com.github.games647.fastlogin.core.auth.LoginSession;
import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent; import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -27,7 +26,7 @@ public class ForceLoginTask extends ForceLoginManagement<Player, CommandSender,
@Override @Override
public void run() { public void run() {
// block this target player for BungeeCord ID brute force attacks // block this target player for proxy ID brute force attacks
FastLoginBukkit plugin = core.getPlugin(); FastLoginBukkit plugin = core.getPlugin();
player.setMetadata(core.getPlugin().getName(), new FixedMetadataValue(plugin, true)); player.setMetadata(core.getPlugin().getName(), new FixedMetadataValue(plugin, true));
@ -56,8 +55,8 @@ public class ForceLoginTask extends ForceLoginManagement<Player, CommandSender,
@Override @Override
public void onForceActionSuccess(LoginSession session) { public void onForceActionSuccess(LoginSession session) {
if (core.getPlugin().getBungeeManager().isEnabled()) { if (core.getPlugin().getProxyManager().isEnabled()) {
core.getPlugin().getBungeeManager().sendPluginMessage(player, new SuccessMessage()); core.getPlugin().getProxyManager().sendPluginMessage(player, new SuccessMessage());
} }
} }

View File

@ -1,8 +1,8 @@
package com.github.games647.fastlogin.bukkit; package com.github.games647.fastlogin.bukkit.auth;
import com.github.games647.craftapi.model.skin.SkinProperty; import com.github.games647.craftapi.model.skin.SkinProperty;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSession; import com.github.games647.fastlogin.core.auth.LoginSession;
import java.util.Optional; import java.util.Optional;
@ -30,7 +30,7 @@ public class BukkitLoginSession extends LoginSession {
this.verifyToken = verifyToken.clone(); this.verifyToken = verifyToken.clone();
} }
//available for BungeeCord // available for proxies
public BukkitLoginSession(String username, boolean registered) { public BukkitLoginSession(String username, boolean registered) {
this(username, "", EMPTY_ARRAY, registered, null); this(username, "", EMPTY_ARRAY, registered, null);
} }
@ -48,7 +48,7 @@ public class BukkitLoginSession extends LoginSession {
/** /**
* Gets the verify token the server sent to the client. * Gets the verify token the server sent to the client.
* *
* Empty if it's a BungeeCord connection * Empty if it's a proxy connection
* *
* @return the verify token from the server * @return the verify token from the server
*/ */

View File

@ -1,4 +1,4 @@
package com.github.games647.fastlogin.bukkit.listener.protocollib; package com.github.games647.fastlogin.bukkit.auth.protocollib;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -10,7 +10,6 @@ import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.Random; import java.util.Random;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
@ -27,7 +26,7 @@ public class EncryptionUtil {
public static final String KEY_PAIR_ALGORITHM = "RSA"; public static final String KEY_PAIR_ALGORITHM = "RSA";
private EncryptionUtil() { private EncryptionUtil() {
//utility // utility
} }
/** /**
@ -43,7 +42,7 @@ public class EncryptionUtil {
keyPairGenerator.initialize(1_024); keyPairGenerator.initialize(1_024);
return keyPairGenerator.generateKeyPair(); return keyPairGenerator.generateKeyPair();
} catch (NoSuchAlgorithmException nosuchalgorithmexception) { } catch (NoSuchAlgorithmException nosuchalgorithmexception) {
//Should be existing in every vm // Should be existing in every vm
throw new ExceptionInInitializerError(nosuchalgorithmexception); throw new ExceptionInInitializerError(nosuchalgorithmexception);
} }
} }
@ -85,7 +84,7 @@ public class EncryptionUtil {
/** /**
* Decrypts the content and extracts the key spec. * Decrypts the content and extracts the key spec.
* *
* @param cipher decryption cipher initialized with the private key * @param privateKey private server key
* @param sharedKey the encrypted shared key * @param sharedKey the encrypted shared key
* @return shared secret key * @return shared secret key
* @throws GeneralSecurityException if it fails to decrypt the data * @throws GeneralSecurityException if it fails to decrypt the data
@ -111,11 +110,13 @@ public class EncryptionUtil {
* @throws GeneralSecurityException if it fails to decrypt the data * @throws GeneralSecurityException if it fails to decrypt the data
*/ */
private static byte[] decrypt(Cipher cipher, byte[] data) throws GeneralSecurityException { private static byte[] decrypt(Cipher cipher, byte[] data) throws GeneralSecurityException {
// inlined: byte[] a(int var0, Key var1, byte[] var2), Cipher a(int var0, String var1, Key var2) // inlined: byte[] a(int var0, Key var1, byte[] var2), Cipher a(int var0, String var1, Key
// var2)
return cipher.doFinal(data); return cipher.doFinal(data);
} }
private static byte[] getServerIdHash(String sessionId, PublicKey publicKey, SecretKey sharedSecret) private static byte[] getServerIdHash(
String sessionId, PublicKey publicKey, SecretKey sharedSecret)
throws NoSuchAlgorithmException { throws NoSuchAlgorithmException {
// byte[] a(String var0, PublicKey var1, SecretKey var2) // byte[] a(String var0, PublicKey var1, SecretKey var2)
MessageDigest digest = MessageDigest.getInstance("SHA-1"); MessageDigest digest = MessageDigest.getInstance("SHA-1");

View File

@ -0,0 +1,23 @@
package com.github.games647.fastlogin.bukkit.auth.protocollib;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerLoginEvent.Result;
public class InitializedListener implements Listener {
private final ProtocolLibListener module;
protected InitializedListener(ProtocolLibListener protocolLibModule) {
this.module = protocolLibModule;
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerLogin(PlayerLoginEvent loginEvent) {
if (loginEvent.getResult() == Result.ALLOWED && !module.isReadyToInject()) {
loginEvent.disallow(Result.KICK_OTHER, module.getPlugin().getCore().getMessage("not-started"));
}
}
}

View File

@ -1,12 +1,12 @@
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.ProtocolLibrary;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.auth.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPreLoginEvent; import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPreLoginEvent;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.JoinManagement; import com.github.games647.fastlogin.core.auth.JoinManagement;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent; import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import java.security.PublicKey; import java.security.PublicKey;
@ -27,7 +27,7 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
private final Player player; private final Player player;
private final String username; private final String username;
public NameCheckTask(FastLoginBukkit plugin, PacketEvent packetEvent, Random random, protected NameCheckTask(FastLoginBukkit plugin, PacketEvent packetEvent, Random random,
Player player, String username, PublicKey publicKey) { Player player, String username, PublicKey publicKey) {
super(plugin.getCore(), plugin.getCore().getAuthPluginHook()); super(plugin.getCore(), plugin.getCore().getAuthPluginHook());
@ -74,7 +74,7 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
byte[] verify = source.getVerifyToken(); byte[] verify = source.getVerifyToken();
BukkitLoginSession playerSession = new BukkitLoginSession(username, serverId, verify, registered, profile); BukkitLoginSession playerSession = new BukkitLoginSession(username, serverId, verify, registered, profile);
plugin.putSession(player.getAddress(), playerSession); plugin.getSessionManager().startLoginSession(player.getAddress(), playerSession);
//cancel only if the player has a paid account otherwise login as normal offline player //cancel only if the player has a paid account otherwise login as normal offline player
synchronized (packetEvent.getAsyncMarker().getProcessingLock()) { synchronized (packetEvent.getAsyncMarker().getProcessingLock()) {
packetEvent.setCancelled(true); packetEvent.setCancelled(true);
@ -84,6 +84,6 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
@Override @Override
public void startCrackedSession(ProtocolLibLoginSource source, StoredProfile profile, String username) { public void startCrackedSession(ProtocolLibLoginSource source, StoredProfile profile, String username) {
BukkitLoginSession loginSession = new BukkitLoginSession(username, profile); BukkitLoginSession loginSession = new BukkitLoginSession(username, profile);
plugin.putSession(player.getAddress(), loginSession); plugin.getSessionManager().startLoginSession(player.getAddress(), loginSession);
} }
} }

View File

@ -1,4 +1,4 @@
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.PacketType;
import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.ProtocolLibrary;
@ -6,12 +6,16 @@ import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.RateLimiter; import com.github.games647.fastlogin.core.auth.RateLimiter;
import io.papermc.lib.PaperLib;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.SecureRandom; import java.security.SecureRandom;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import static com.comphenix.protocol.PacketType.Login.Client.ENCRYPTION_BEGIN; import static com.comphenix.protocol.PacketType.Login.Client.ENCRYPTION_BEGIN;
import static com.comphenix.protocol.PacketType.Login.Client.START; import static com.comphenix.protocol.PacketType.Login.Client.START;
@ -25,7 +29,11 @@ public class ProtocolLibListener extends PacketAdapter {
private final KeyPair keyPair = EncryptionUtil.generateKeyPair(); private final KeyPair keyPair = EncryptionUtil.generateKeyPair();
private final RateLimiter rateLimiter; private final RateLimiter rateLimiter;
public ProtocolLibListener(FastLoginBukkit plugin, RateLimiter rateLimiter) { // Wait before the server is fully started. This is workaround, because connections right on startup are not
// injected by ProtocolLib
private boolean serverStarted;
protected ProtocolLibListener(FastLoginBukkit plugin, RateLimiter rateLimiter) {
//run async in order to not block the server, because we are making api calls to Mojang //run async in order to not block the server, because we are making api calls to Mojang
super(params() super(params()
.plugin(plugin) .plugin(plugin)
@ -38,20 +46,29 @@ public class ProtocolLibListener extends PacketAdapter {
public static void register(FastLoginBukkit plugin, RateLimiter rateLimiter) { public static void register(FastLoginBukkit plugin, RateLimiter rateLimiter) {
//they will be created with a static builder, because otherwise it will throw a NoClassDefFoundError //they will be created with a static builder, because otherwise it will throw a NoClassDefFoundError
ProtocolLibListener packetListener = new ProtocolLibListener(plugin, rateLimiter);
ProtocolLibrary.getProtocolManager() ProtocolLibrary.getProtocolManager()
.getAsynchronousManager() .getAsynchronousManager()
.registerAsyncHandler(new ProtocolLibListener(plugin, rateLimiter)) .registerAsyncHandler(packetListener)
.start(); .start();
PluginManager pluginManager = Bukkit.getServer().getPluginManager();
pluginManager.registerEvents(new InitializedListener(packetListener), plugin);
//if server is using paper - we need to set the skin at pre login anyway, so no need for this listener
if (!PaperLib.isPaper() && plugin.getConfig().getBoolean("forwardSkin")) {
pluginManager.registerEvents(new SkinApplyListener(plugin), plugin);
}
} }
@Override @Override
public void onPacketReceiving(PacketEvent packetEvent) { public void onPacketReceiving(PacketEvent packetEvent) {
if (packetEvent.isCancelled() if (packetEvent.isCancelled() || plugin.getCore().getAuthPluginHook() == null) {
|| plugin.getCore().getAuthPluginHook()== null
|| !plugin.isServerFullyStarted()) {
return; return;
} }
markReadyToInject();
Player sender = packetEvent.getPlayer(); Player sender = packetEvent.getPlayer();
PacketType packetType = packetEvent.getPacketType(); PacketType packetType = packetEvent.getPacketType();
if (packetType == START) { if (packetType == START) {
@ -79,7 +96,7 @@ public class ProtocolLibListener extends PacketAdapter {
String sessionKey = player.getAddress().toString(); String sessionKey = player.getAddress().toString();
//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(player.getAddress()); plugin.getSessionManager().endLoginSession(player.getAddress());
//player.getName() won't work at this state //player.getName() won't work at this state
PacketContainer packet = packetEvent.getPacket(); PacketContainer packet = packetEvent.getPacket();
@ -91,4 +108,17 @@ public class ProtocolLibListener extends PacketAdapter {
Runnable nameCheckTask = new NameCheckTask(plugin, packetEvent, random, player, username, keyPair.getPublic()); Runnable nameCheckTask = new NameCheckTask(plugin, packetEvent, random, player, username, keyPair.getPublic());
plugin.getScheduler().runAsync(nameCheckTask); plugin.getScheduler().runAsync(nameCheckTask);
} }
public void markReadyToInject() {
this.serverStarted = true;
}
public boolean isReadyToInject() {
return serverStarted;
}
@Override
public FastLoginBukkit getPlugin() {
return plugin;
}
} }

View File

@ -1,4 +1,4 @@
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.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager; import com.comphenix.protocol.ProtocolManager;
@ -6,7 +6,7 @@ import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.wrappers.WrappedChatComponent; import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.github.games647.fastlogin.core.shared.LoginSource; import com.github.games647.fastlogin.core.auth.LoginSource;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@ -30,7 +30,7 @@ class ProtocolLibLoginSource implements LoginSource {
private final String serverId = ""; private final String serverId = "";
private byte[] verifyToken; private byte[] verifyToken;
public ProtocolLibLoginSource(PacketEvent packetEvent, Player player, Random random, PublicKey publicKey) { protected ProtocolLibLoginSource(PacketEvent packetEvent, Player player, Random random, PublicKey publicKey) {
this.packetEvent = packetEvent; this.packetEvent = packetEvent;
this.player = player; this.player = player;
this.random = random; this.random = random;

View File

@ -1,14 +1,14 @@
package com.github.games647.fastlogin.bukkit.listener.protocollib; package com.github.games647.fastlogin.bukkit.auth.protocollib;
import com.comphenix.protocol.reflect.MethodUtils;
import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.MethodAccessor; import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.WrappedGameProfile; import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.comphenix.protocol.wrappers.WrappedSignedProperty; import com.comphenix.protocol.wrappers.WrappedSignedProperty;
import com.github.games647.craftapi.model.skin.Textures; import com.github.games647.craftapi.model.skin.Textures;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.auth.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
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;
@ -16,8 +16,6 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerLoginEvent.Result; import org.bukkit.event.player.PlayerLoginEvent.Result;
import java.lang.reflect.InvocationTargetException;
public class SkinApplyListener implements Listener { public class SkinApplyListener implements Listener {
private static final Class<?> GAME_PROFILE = MinecraftReflection.getGameProfileClass(); private static final Class<?> GAME_PROFILE = MinecraftReflection.getGameProfileClass();
@ -25,7 +23,7 @@ public class SkinApplyListener implements Listener {
private final FastLoginBukkit plugin; private final FastLoginBukkit plugin;
public SkinApplyListener(FastLoginBukkit plugin) { protected SkinApplyListener(FastLoginBukkit plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@ -40,28 +38,15 @@ public class SkinApplyListener implements Listener {
//go through every session, because player.getAddress is null //go through every session, because player.getAddress is null
//loginEvent.getAddress is just a InetAddress not InetSocketAddress, so not unique enough //loginEvent.getAddress is just a InetAddress not InetSocketAddress, so not unique enough
for (BukkitLoginSession session : plugin.getLoginSessions().values()) { BukkitLoginSession session = plugin.getSessionManager().getLoginSession(player.getAddress());
if (session.getUsername().equals(player.getName())) { if (session.getUsername().equals(player.getName())) {
session.getSkin().ifPresent(skin -> applySkin(player, skin.getValue(), skin.getSignature())); session.getSkin().ifPresent(skin -> applySkin(player, skin.getValue(), skin.getSignature()));
break;
}
} }
} }
private void applySkin(Player player, String skinData, String signature) { private void applySkin(Player player, String skinData, String signature) {
WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(player); WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(player);
WrappedSignedProperty skin = WrappedSignedProperty.fromValues(Textures.KEY, skinData, signature); WrappedSignedProperty skin = WrappedSignedProperty.fromValues(Textures.KEY, skinData, signature);
try {
gameProfile.getProperties().put(Textures.KEY, skin); gameProfile.getProperties().put(Textures.KEY, skin);
} catch (ClassCastException castException) {
//Cauldron, MCPC, Thermos, ...
Object map = GET_PROPERTIES.invoke(gameProfile.getHandle());
try {
MethodUtils.invokeMethod(map, "put", new Object[]{Textures.KEY, skin.getHandle()});
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
plugin.getLog().error("Error setting premium skin of: {}", player, ex);
}
}
} }
} }

View File

@ -1,4 +1,4 @@
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.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
@ -12,12 +12,9 @@ import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.github.games647.craftapi.model.auth.Verification; import com.github.games647.craftapi.model.auth.Verification;
import com.github.games647.craftapi.model.skin.SkinProperty; import com.github.games647.craftapi.model.skin.SkinProperty;
import com.github.games647.craftapi.resolver.MojangResolver; import com.github.games647.craftapi.resolver.MojangResolver;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.auth.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import org.bukkit.entity.Player;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -31,6 +28,11 @@ import java.util.Arrays;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import org.bukkit.entity.Player;
import static com.comphenix.protocol.PacketType.Login.Client.START; import static com.comphenix.protocol.PacketType.Login.Client.START;
import static com.comphenix.protocol.PacketType.Login.Server.DISCONNECT; import static com.comphenix.protocol.PacketType.Login.Server.DISCONNECT;
@ -47,7 +49,7 @@ public class VerifyResponseTask implements Runnable {
private static Method encryptMethod; private static Method encryptMethod;
private static Method cipherMethod; private static Method cipherMethod;
public VerifyResponseTask(FastLoginBukkit plugin, PacketEvent packetEvent, Player player, protected VerifyResponseTask(FastLoginBukkit plugin, PacketEvent packetEvent, Player player,
byte[] sharedSecret, KeyPair keyPair) { byte[] sharedSecret, KeyPair keyPair) {
this.plugin = plugin; this.plugin = plugin;
this.packetEvent = packetEvent; this.packetEvent = packetEvent;
@ -59,7 +61,7 @@ public class VerifyResponseTask implements Runnable {
@Override @Override
public void run() { public void run() {
try { try {
BukkitLoginSession session = plugin.getSession(player.getAddress()); BukkitLoginSession session = plugin.getSessionManager().getLoginSession(player.getAddress());
if (session == null) { if (session == null) {
disconnect("invalid-request", true disconnect("invalid-request", true
, "GameProfile {0} tried to send encryption response at invalid state", player.getAddress()); , "GameProfile {0} tried to send encryption response at invalid state", player.getAddress());

View File

@ -1,6 +1,6 @@
package com.github.games647.fastlogin.bukkit.listener.protocolsupport; package com.github.games647.fastlogin.bukkit.auth.protocolsupport;
import com.github.games647.fastlogin.core.shared.LoginSource; import com.github.games647.fastlogin.core.auth.LoginSource;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@ -10,7 +10,7 @@ public class ProtocolLoginSource implements LoginSource {
private final PlayerLoginStartEvent loginStartEvent; private final PlayerLoginStartEvent loginStartEvent;
public ProtocolLoginSource(PlayerLoginStartEvent loginStartEvent) { protected ProtocolLoginSource(PlayerLoginStartEvent loginStartEvent) {
this.loginStartEvent = loginStartEvent; this.loginStartEvent = loginStartEvent;
} }

View File

@ -1,12 +1,12 @@
package com.github.games647.fastlogin.bukkit.listener.protocolsupport; package com.github.games647.fastlogin.bukkit.auth.protocolsupport;
import com.github.games647.craftapi.UUIDAdapter; import com.github.games647.craftapi.UUIDAdapter;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.auth.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPreLoginEvent; import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPreLoginEvent;
import com.github.games647.fastlogin.core.RateLimiter; import com.github.games647.fastlogin.core.auth.RateLimiter;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.JoinManagement; import com.github.games647.fastlogin.core.auth.JoinManagement;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent; import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@ -48,7 +48,7 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
InetSocketAddress address = loginStartEvent.getAddress(); InetSocketAddress address = loginStartEvent.getAddress();
//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.getSessionManager().endLoginSession(address);
super.onLogin(username, new ProtocolLoginSource(loginStartEvent)); super.onLogin(username, new ProtocolLoginSource(loginStartEvent));
} }
@ -56,13 +56,13 @@ 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().getAddress();
plugin.removeSession(address); plugin.getSessionManager().endLoginSession(address);
} }
@EventHandler @EventHandler
public void onPropertiesResolve(PlayerProfileCompleteEvent profileCompleteEvent) { public void onPropertiesResolve(PlayerProfileCompleteEvent profileCompleteEvent) {
InetSocketAddress address = profileCompleteEvent.getAddress(); InetSocketAddress address = profileCompleteEvent.getAddress();
BukkitLoginSession session = plugin.getSession(address); BukkitLoginSession session = plugin.getSessionManager().getLoginSession(address);
if (session != null && profileCompleteEvent.getConnection().getProfile().isOnlineMode()) { if (session != null && profileCompleteEvent.getConnection().getProfile().isOnlineMode()) {
session.setVerified(true); session.setVerified(true);
@ -91,12 +91,12 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
plugin.getCore().getPendingLogin().put(ip + username, new Object()); plugin.getCore().getPendingLogin().put(ip + username, new Object());
BukkitLoginSession playerSession = new BukkitLoginSession(username, registered, profile); BukkitLoginSession playerSession = new BukkitLoginSession(username, registered, profile);
plugin.putSession(source.getAddress(), playerSession); plugin.getSessionManager().startLoginSession(source.getAddress(), playerSession);
} }
@Override @Override
public void startCrackedSession(ProtocolLoginSource source, StoredProfile profile, String username) { public void startCrackedSession(ProtocolLoginSource source, StoredProfile profile, String username) {
BukkitLoginSession loginSession = new BukkitLoginSession(username, profile); BukkitLoginSession loginSession = new BukkitLoginSession(username, profile);
plugin.putSession(source.getAddress(), loginSession); plugin.getSessionManager().startLoginSession(source.getAddress(), loginSession);
} }
} }

View File

@ -1,6 +1,6 @@
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.core.message.ChannelMessage; import com.github.games647.fastlogin.core.message.ChannelMessage;
import com.github.games647.fastlogin.core.message.LoginActionMessage; import com.github.games647.fastlogin.core.message.LoginActionMessage;
import com.github.games647.fastlogin.core.message.NamespaceKey; import com.github.games647.fastlogin.core.message.NamespaceKey;
@ -25,12 +25,12 @@ import static com.github.games647.fastlogin.core.message.ChangePremiumMessage.CH
import static com.github.games647.fastlogin.core.message.SuccessMessage.SUCCESS_CHANNEL; import static com.github.games647.fastlogin.core.message.SuccessMessage.SUCCESS_CHANNEL;
import static java.util.stream.Collectors.toSet; import static java.util.stream.Collectors.toSet;
public class BungeeManager { public class ProxyManager {
private static final String LEGACY_FILE_NAME = "proxy-whitelist.txt"; private static final String LEGACY_FILE_NAME = "proxy-whitelist.txt";
private static final String FILE_NAME = "allowed-proxies.txt"; private static final String FILE_NAME = "allowed-proxies.txt";
//null if proxies allowed list is empty so bungeecord support is disabled //null if proxies allowed list is empty so proxy support is disabled
private Set<UUID> proxyIds; private Set<UUID> proxyIds;
private final FastLoginBukkit plugin; private final FastLoginBukkit plugin;
@ -38,7 +38,7 @@ public class BungeeManager {
private final Set<UUID> firedJoinEvents = new HashSet<>(); private final Set<UUID> firedJoinEvents = new HashSet<>();
public BungeeManager(FastLoginBukkit plugin) { public ProxyManager(FastLoginBukkit plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@ -63,23 +63,23 @@ public class BungeeManager {
public void initialize() { public void initialize() {
try { try {
enabled = detectBungeeCord(); enabled = detectProxy();
} catch (Exception ex) { } catch (Exception ex) {
plugin.getLog().warn("Cannot check bungeecord support. Fallback to non-bungee mode", ex); plugin.getLog().warn("Cannot check proxy support. Fallback to non-proxy mode", ex);
} }
if (enabled) { if (enabled) {
proxyIds = loadBungeeCordIds(); proxyIds = loadProxyIds();
registerPluginChannels(); registerPluginChannels();
} }
} }
private boolean detectBungeeCord() throws Exception { private boolean detectProxy() throws Exception {
try { try {
enabled = Class.forName("org.spigotmc.SpigotConfig").getDeclaredField("bungee").getBoolean(null); enabled = Class.forName("org.spigotmc.SpigotConfig").getDeclaredField("bungee").getBoolean(null);
return enabled; return enabled;
} catch (ClassNotFoundException notFoundEx) { } catch (ClassNotFoundException notFoundEx) {
//ignore server has no bungee support //ignore server has no proxy support
return false; return false;
} catch (Exception ex) { } catch (Exception ex) {
throw ex; throw ex;
@ -89,10 +89,10 @@ public class BungeeManager {
private void registerPluginChannels() { private void registerPluginChannels() {
Server server = Bukkit.getServer(); Server server = Bukkit.getServer();
// check for incoming messages from the bungeecord version of this plugin // check for incoming messages from the proxy version of this plugin
String groupId = plugin.getName(); String groupId = plugin.getName();
String forceChannel = NamespaceKey.getCombined(groupId, LoginActionMessage.FORCE_CHANNEL); String forceChannel = NamespaceKey.getCombined(groupId, LoginActionMessage.FORCE_CHANNEL);
server.getMessenger().registerIncomingPluginChannel(plugin, forceChannel, new BungeeListener(plugin)); server.getMessenger().registerIncomingPluginChannel(plugin, forceChannel, new ProxyMessagingListener(plugin));
// outgoing // outgoing
String successChannel = new NamespaceKey(groupId, SUCCESS_CHANNEL).getCombinedName(); String successChannel = new NamespaceKey(groupId, SUCCESS_CHANNEL).getCombinedName();
@ -101,7 +101,7 @@ public class BungeeManager {
server.getMessenger().registerOutgoingPluginChannel(plugin, changeChannel); server.getMessenger().registerOutgoingPluginChannel(plugin, changeChannel);
} }
private Set<UUID> loadBungeeCordIds() { private Set<UUID> loadProxyIds() {
Path proxiesFile = plugin.getPluginFolder().resolve(FILE_NAME); Path proxiesFile = plugin.getPluginFolder().resolve(FILE_NAME);
Path legacyFile = plugin.getPluginFolder().resolve(LEGACY_FILE_NAME); Path legacyFile = plugin.getPluginFolder().resolve(LEGACY_FILE_NAME);
try { try {
@ -124,7 +124,7 @@ public class BungeeManager {
} catch (IOException ex) { } catch (IOException ex) {
plugin.getLog().error("Failed to read proxies", ex); plugin.getLog().error("Failed to read proxies", ex);
} catch (Exception ex) { } catch (Exception ex) {
plugin.getLog().error("Failed to retrieve proxy Id. Disabling BungeeCord support", ex); plugin.getLog().error("Failed to retrieve proxy Id. Disabling proxy support", ex);
} }
return Collections.emptySet(); return Collections.emptySet();
@ -145,7 +145,7 @@ public class BungeeManager {
/** /**
* Check if the event fired including with the task delay. This necessary to restore the order of processing the * 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. * proxy 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 * 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 * session. If not fired, we can start a new force login task. This will still match the requirement that we wait

View File

@ -1,8 +1,8 @@
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.auth.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.task.ForceLoginTask; import com.github.games647.fastlogin.bukkit.ForceLoginTask;
import com.github.games647.fastlogin.core.PremiumStatus; import com.github.games647.fastlogin.core.PremiumStatus;
import com.github.games647.fastlogin.core.hooks.AuthPlugin; import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.message.LoginActionMessage; import com.github.games647.fastlogin.core.message.LoginActionMessage;
@ -18,16 +18,16 @@ import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener; import org.bukkit.plugin.messaging.PluginMessageListener;
/** /**
* Responsible for receiving messages from a BungeeCord instance. * Responsible for receiving messages from a proxy instance.
* *
* This class also receives the plugin message from the bungeecord version of this plugin in order to get notified if * This class also receives the plugin message from the proxy version of this plugin in order to get notified if
* the connection is in online mode. * the connection is in online mode.
*/ */
public class BungeeListener implements PluginMessageListener { public class ProxyMessagingListener implements PluginMessageListener {
private final FastLoginBukkit plugin; private final FastLoginBukkit plugin;
public BungeeListener(FastLoginBukkit plugin) { protected ProxyMessagingListener(FastLoginBukkit plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@ -50,12 +50,12 @@ public class BungeeListener implements PluginMessageListener {
return; return;
} }
// fail if target player is blocked because already authenticated or wrong bungeecord id // fail if target player is blocked because already authenticated or wrong proxy id
if (targetPlayer.hasMetadata(plugin.getName())) { if (targetPlayer.hasMetadata(plugin.getName())) {
plugin.getLog().warn("Received message {} from a blocked player {}", loginMessage, targetPlayer); plugin.getLog().warn("Received message {} from a blocked player {}", loginMessage, targetPlayer);
} else { } else {
UUID sourceId = loginMessage.getProxyId(); UUID sourceId = loginMessage.getProxyId();
if (plugin.getBungeeManager().isProxyAllowed(sourceId)) { if (plugin.getProxyManager().isProxyAllowed(sourceId)) {
readMessage(targetPlayer, loginMessage); readMessage(targetPlayer, loginMessage);
} else { } else {
plugin.getLog().warn("Received proxy id: {} that doesn't exist in the proxy file", sourceId); plugin.getLog().warn("Received proxy id: {} that doesn't exist in the proxy file", sourceId);
@ -101,10 +101,10 @@ 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.getSessionManager().startLoginSession(player.getAddress(), 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.getProxyManager().didJoinEventFired(player);
plugin.getLog().info("Delaying force login until join event fired?: {}", result); plugin.getLog().info("Delaying force login until join event fired?: {}", result);
if (result) { if (result) {
Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session); Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);

View File

@ -2,9 +2,8 @@ package com.github.games647.fastlogin.bukkit.command;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPremiumToggleEvent; import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPremiumToggleEvent;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -36,8 +35,8 @@ public class CrackedCommand extends ToggleCommand {
return; return;
} }
if (plugin.getBungeeManager().isEnabled()) { if (plugin.getProxyManager().isEnabled()) {
sendBungeeActivateMessage(sender, sender.getName(), false); sendProxyActivateMessage(sender, sender.getName(), false);
plugin.getCore().sendLocaleMessage("wait-on-proxy", sender); plugin.getCore().sendLocaleMessage("wait-on-proxy", sender);
} else { } else {
//todo: load async if //todo: load async if
@ -90,6 +89,6 @@ public class CrackedCommand extends ToggleCommand {
} }
private boolean forwardCrackedCommand(CommandSender sender, String target) { private boolean forwardCrackedCommand(CommandSender sender, String target) {
return forwardBungeeCommand(sender, target, false); return forwardProxyCommand(sender, target, false);
} }
} }

View File

@ -2,12 +2,11 @@ package com.github.games647.fastlogin.bukkit.command;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPremiumToggleEvent; import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPremiumToggleEvent;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent.PremiumToggleReason;
import com.github.games647.fastlogin.core.storage.StoredProfile;
import java.util.UUID; import java.util.UUID;
import com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent;
import com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent.PremiumToggleReason;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -100,6 +99,6 @@ public class PremiumCommand extends ToggleCommand {
} }
private boolean forwardPremiumCommand(CommandSender sender, String target) { private boolean forwardPremiumCommand(CommandSender sender, String target) {
return forwardBungeeCommand(sender, target, true); return forwardProxyCommand(sender, target, true);
} }
} }

View File

@ -30,9 +30,9 @@ public abstract class ToggleCommand implements CommandExecutor {
return true; return true;
} }
protected boolean forwardBungeeCommand(CommandSender sender, String target, boolean activate) { protected boolean forwardProxyCommand(CommandSender sender, String target, boolean activate) {
if (plugin.getBungeeManager().isEnabled()) { if (plugin.getProxyManager().isEnabled()) {
sendBungeeActivateMessage(sender, target, activate); sendProxyActivateMessage(sender, target, activate);
plugin.getCore().sendLocaleMessage("wait-on-proxy", sender); plugin.getCore().sendLocaleMessage("wait-on-proxy", sender);
return true; return true;
} }
@ -50,10 +50,10 @@ public abstract class ToggleCommand implements CommandExecutor {
return true; return true;
} }
protected void sendBungeeActivateMessage(CommandSender invoker, String target, boolean activate) { protected void sendProxyActivateMessage(CommandSender invoker, String target, boolean activate) {
if (invoker instanceof PluginMessageRecipient) { if (invoker instanceof PluginMessageRecipient) {
ChannelMessage message = new ChangePremiumMessage(target, activate, true); ChannelMessage message = new ChangePremiumMessage(target, activate, true);
plugin.getBungeeManager().sendPluginMessage((PluginMessageRecipient) invoker, message); plugin.getProxyManager().sendPluginMessage((PluginMessageRecipient) invoker, message);
} else { } else {
Optional<? extends Player> optPlayer = Bukkit.getServer().getOnlinePlayers().stream().findFirst(); Optional<? extends Player> optPlayer = Bukkit.getServer().getOnlinePlayers().stream().findFirst();
if (!optPlayer.isPresent()) { if (!optPlayer.isPresent()) {
@ -63,7 +63,7 @@ public abstract class ToggleCommand implements CommandExecutor {
Player sender = optPlayer.get(); Player sender = optPlayer.get();
ChannelMessage message = new ChangePremiumMessage(target, activate, false); ChannelMessage message = new ChangePremiumMessage(target, activate, false);
plugin.getBungeeManager().sendPluginMessage(sender, message); plugin.getProxyManager().sendPluginMessage(sender, message);
} }
} }
} }

View File

@ -1,7 +1,7 @@
package com.github.games647.fastlogin.bukkit.event; package com.github.games647.fastlogin.bukkit.event;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSession; import com.github.games647.fastlogin.core.auth.LoginSession;
import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent; import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent;
import org.bukkit.event.Cancellable; import org.bukkit.event.Cancellable;
import org.bukkit.event.Event; import org.bukkit.event.Event;

View File

@ -1,7 +1,7 @@
package com.github.games647.fastlogin.bukkit.event; package com.github.games647.fastlogin.bukkit.event;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSource; import com.github.games647.fastlogin.core.auth.LoginSource;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent; import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;

View File

@ -1,6 +1,6 @@
package com.github.games647.fastlogin.bukkit.event; package com.github.games647.fastlogin.bukkit.event;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent; import com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;

View File

@ -1,20 +1,22 @@
package com.github.games647.fastlogin.bukkit.hook; 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.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.storage.StoredProfile;
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>
@ -31,7 +33,7 @@ public class AuthMeHook implements AuthPlugin<Player>, Listener {
private final AuthMeApi authmeAPI; private final AuthMeApi authmeAPI;
private Management authmeManagement; private Management authmeManagement;
public AuthMeHook(FastLoginBukkit plugin) { protected AuthMeHook(FastLoginBukkit plugin) {
this.plugin = plugin; this.plugin = plugin;
this.authmeAPI = AuthMeApi.getInstance(); this.authmeAPI = AuthMeApi.getInstance();
@ -50,8 +52,8 @@ 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()); StoredProfile session = plugin.getSessionManager().getPlaySession(player.getUniqueId());
if (session != null && session.isVerified()) { if (session != null && session.isPremium()) {
restoreSessionEvent.setCancelled(true); restoreSessionEvent.setCancelled(true);
} }
} }

View File

@ -31,7 +31,7 @@ public class CrazyLoginHook implements AuthPlugin<Player> {
private final CrazyLogin crazyLoginPlugin; private final CrazyLogin crazyLoginPlugin;
private final PlayerListener playerListener; private final PlayerListener playerListener;
public CrazyLoginHook(FastLoginBukkit plugin) { protected CrazyLoginHook(FastLoginBukkit plugin) {
this.plugin = plugin; this.plugin = plugin;
crazyLoginPlugin = CrazyLogin.getPlugin(); crazyLoginPlugin = CrazyLogin.getPlugin();

View File

@ -1,13 +1,6 @@
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.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.bukkit.hook.SodionAuthHook;
import com.github.games647.fastlogin.core.hooks.AuthPlugin; import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -29,18 +22,14 @@ public class DelayedAuthHook implements Runnable {
@Override @Override
public void run() { public void run() {
boolean hookFound = isHookFound(); boolean hookFound = isHookFound();
if (plugin.getBungeeManager().isEnabled()) { if (plugin.getProxyManager().isEnabled()) {
plugin.getLog().info("BungeeCord setting detected. No auth plugin is required"); plugin.getLog().info("Proxy setting detected. No auth plugin is required");
} else if (!hookFound) { } else if (!hookFound) {
plugin.getLog().warn("No auth plugin were found by this plugin " plugin.getLog().warn("No auth plugin were found by this plugin "
+ "(other plugins could hook into this after the initialization of this plugin)" + "(other plugins could hook into this after the initialization of this plugin)"
+ "and BungeeCord is deactivated. " + "and BungeeCord (or similar proxies) is deactivated. "
+ "Either one or both of the checks have to pass in order to use this plugin"); + "Either one or both of the checks have to pass in order to use this plugin");
} }
if (hookFound) {
plugin.markInitialized();
}
} }
private boolean isHookFound() { private boolean isHookFound() {

View File

@ -25,7 +25,7 @@ public class LogItHook implements AuthPlugin<Player> {
private final FastLoginBukkit plugin; private final FastLoginBukkit plugin;
public LogItHook(FastLoginBukkit plugin) { protected LogItHook(FastLoginBukkit plugin) {
this.plugin = plugin; this.plugin = plugin;
} }

View File

@ -23,7 +23,7 @@ public class LoginSecurityHook implements AuthPlugin<Player> {
private final FastLoginBukkit plugin; private final FastLoginBukkit plugin;
public LoginSecurityHook(FastLoginBukkit plugin) { protected LoginSecurityHook(FastLoginBukkit plugin) {
this.plugin = plugin; this.plugin = plugin;
} }

View File

@ -20,7 +20,7 @@ public class SodionAuthHook implements AuthPlugin<Player> {
private final FastLoginBukkit plugin; private final FastLoginBukkit plugin;
public SodionAuthHook(FastLoginBukkit plugin) { protected SodionAuthHook(FastLoginBukkit plugin) {
this.plugin = plugin; this.plugin = plugin;
} }

View File

@ -25,7 +25,7 @@ public class UltraAuthHook implements AuthPlugin<Player> {
private final Plugin ultraAuthPlugin = Main.main; private final Plugin ultraAuthPlugin = Main.main;
private final FastLoginBukkit plugin; private final FastLoginBukkit plugin;
public UltraAuthHook(FastLoginBukkit plugin) { protected UltraAuthHook(FastLoginBukkit plugin) {
this.plugin = plugin; this.plugin = plugin;
} }

View File

@ -24,7 +24,7 @@ public class xAuthHook implements AuthPlugin<Player> {
private final xAuth xAuthPlugin = xAuth.getPlugin(); private final xAuth xAuthPlugin = xAuth.getPlugin();
private final FastLoginBukkit plugin; private final FastLoginBukkit plugin;
public xAuthHook(FastLoginBukkit plugin) { protected xAuthHook(FastLoginBukkit plugin) {
this.plugin = plugin; this.plugin = plugin;
} }

View File

@ -1,8 +1,8 @@
package com.github.games647.fastlogin.bukkit.listener; package com.github.games647.fastlogin.bukkit.listener;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.auth.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.task.ForceLoginTask; import com.github.games647.fastlogin.bukkit.ForceLoginTask;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -11,7 +11,6 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerLoginEvent.Result;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
/** /**
@ -31,9 +30,6 @@ public class ConnectionListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void onPlayerLogin(PlayerLoginEvent loginEvent) { public void onPlayerLogin(PlayerLoginEvent loginEvent) {
removeBlockedStatus(loginEvent.getPlayer()); removeBlockedStatus(loginEvent.getPlayer());
if (loginEvent.getResult() == Result.ALLOWED && !plugin.isServerFullyStarted()) {
loginEvent.disallow(Result.KICK_OTHER, plugin.getCore().getMessage("not-started"));
}
} }
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
@ -42,18 +38,15 @@ public class ConnectionListener implements Listener {
Bukkit.getScheduler().runTaskLater(plugin, () -> { Bukkit.getScheduler().runTaskLater(plugin, () -> {
// 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 proxy message before PlayerJoinEvent) or not running proxy 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.getSessionManager().getLoginSession(player.getAddress());
if (session == null) { 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); Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);
Bukkit.getScheduler().runTaskAsynchronously(plugin, forceLoginTask); Bukkit.getScheduler().runTaskAsynchronously(plugin, forceLoginTask);
} }
plugin.getBungeeManager().markJoinEventFired(player); plugin.getProxyManager().markJoinEventFired(player);
// delay the login process to let auth plugins initialize the player // delay the login process to let auth plugins initialize the player
// Magic number however as there is no direct event from those plugins // Magic number however as there is no direct event from those plugins
}, DELAY_LOGIN); }, DELAY_LOGIN);
@ -66,7 +59,7 @@ public class ConnectionListener implements Listener {
removeBlockedStatus(player); removeBlockedStatus(player);
plugin.getCore().getPendingConfirms().remove(player.getUniqueId()); plugin.getCore().getPendingConfirms().remove(player.getUniqueId());
plugin.getPremiumPlayers().remove(player.getUniqueId()); plugin.getPremiumPlayers().remove(player.getUniqueId());
plugin.getBungeeManager().cleanup(player); plugin.getProxyManager().cleanup(player);
} }
private void removeBlockedStatus(Player player) { private void removeBlockedStatus(Player player) {

View File

@ -2,8 +2,9 @@ package com.github.games647.fastlogin.bukkit.listener;
import com.destroystokyo.paper.profile.ProfileProperty; import com.destroystokyo.paper.profile.ProfileProperty;
import com.github.games647.craftapi.model.skin.Textures; import com.github.games647.craftapi.model.skin.Textures;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.auth.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
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;
@ -27,7 +28,7 @@ public class PaperPreLoginListener implements Listener {
} }
// event gives us only IP, not the port, so we need to loop through all the sessions // event gives us only IP, not the port, so we need to loop through all the sessions
for (BukkitLoginSession session : plugin.getLoginSessions().values()) { for (BukkitLoginSession session : plugin.getSessionManager().getLoginSessions().values()) {
if (!event.getName().equals(session.getUsername())) { if (!event.getName().equals(session.getUsername())) {
continue; continue;
} }

View File

@ -1,5 +1,7 @@
package com.github.games647.fastlogin.bukkit.listener.protocollib; package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.github.games647.fastlogin.bukkit.auth.protocollib.EncryptionUtil;
import java.security.SecureRandom; import java.security.SecureRandom;
import org.junit.Test; import org.junit.Test;

View File

@ -21,7 +21,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.2.3</version> <version>3.2.4</version>
<configuration> <configuration>
<createDependencyReducedPom>false</createDependencyReducedPom> <createDependencyReducedPom>false</createDependencyReducedPom>
<shadedArtifactAttached>false</shadedArtifactAttached> <shadedArtifactAttached>false</shadedArtifactAttached>
@ -56,7 +56,6 @@
</build> </build>
<repositories> <repositories>
<repository> <repository>
<id>codemc-repo</id> <id>codemc-repo</id>
<url>https://repo.codemc.io/repository/maven-public/</url> <url>https://repo.codemc.io/repository/maven-public/</url>
@ -71,7 +70,6 @@
<id>spigotplugins-repo</id> <id>spigotplugins-repo</id>
<url>https://maven.gamestrike.de/mvn/</url> <url>https://maven.gamestrike.de/mvn/</url>
</repository> </repository>
</repositories> </repositories>
<dependencies> <dependencies>
@ -86,7 +84,7 @@
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>net.md-5</groupId>
<artifactId>bungeecord-proxy</artifactId> <artifactId>bungeecord-proxy</artifactId>
<version>1.15-SNAPSHOT</version> <version>1.16-R0.5-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>

View File

@ -1,7 +1,7 @@
package com.github.games647.fastlogin.bungee; package com.github.games647.fastlogin.bungee;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSession; import com.github.games647.fastlogin.core.auth.LoginSession;
public class BungeeLoginSession extends LoginSession { public class BungeeLoginSession extends LoginSession {

View File

@ -1,6 +1,6 @@
package com.github.games647.fastlogin.bungee; package com.github.games647.fastlogin.bungee;
import com.github.games647.fastlogin.core.shared.LoginSource; import com.github.games647.fastlogin.core.auth.LoginSource;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;

View File

@ -0,0 +1,23 @@
package com.github.games647.fastlogin.bungee;
import com.github.games647.fastlogin.core.SessionManager;
import java.util.UUID;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
public class BungeeSessionManager extends SessionManager<PlayerDisconnectEvent, PendingConnection, BungeeLoginSession>
implements Listener {
//todo: memory leak on cancelled login event
@EventHandler
public void onPlayQuit(PlayerDisconnectEvent disconnectEvent) {
ProxiedPlayer player = disconnectEvent.getPlayer();
UUID playerId = player.getUniqueId();
endPlaySession(playerId);
}
}

View File

@ -12,18 +12,15 @@ import com.github.games647.fastlogin.core.message.NamespaceKey;
import com.github.games647.fastlogin.core.message.SuccessMessage; import com.github.games647.fastlogin.core.message.SuccessMessage;
import com.github.games647.fastlogin.core.shared.FastLoginCore; import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.PlatformPlugin; import com.github.games647.fastlogin.core.shared.PlatformPlugin;
import com.google.common.collect.MapMaker;
import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.Server; import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.Plugin;
@ -37,7 +34,7 @@ import org.slf4j.Logger;
*/ */
public class FastLoginBungee extends Plugin implements PlatformPlugin<CommandSender> { public class FastLoginBungee extends Plugin implements PlatformPlugin<CommandSender> {
private final ConcurrentMap<PendingConnection, BungeeLoginSession> session = new MapMaker().weakKeys().makeMap(); private final BungeeSessionManager sessionManager = new BungeeSessionManager();
private FastLoginCore<ProxiedPlayer, CommandSender, FastLoginBungee> core; private FastLoginCore<ProxiedPlayer, CommandSender, FastLoginBungee> core;
private AsyncScheduler scheduler; private AsyncScheduler scheduler;
@ -80,10 +77,6 @@ public class FastLoginBungee extends Plugin implements PlatformPlugin<CommandSen
return core; return core;
} }
public ConcurrentMap<PendingConnection, BungeeLoginSession> getSession() {
return session;
}
private void registerHook() { private void registerHook() {
Plugin BungeeAuth = getProxy().getPluginManager().getPlugin("BungeeAuth"); Plugin BungeeAuth = getProxy().getPluginManager().getPlugin("BungeeAuth");
if (BungeeAuth != null) { if (BungeeAuth != null) {

View File

@ -1,7 +1,7 @@
package com.github.games647.fastlogin.bungee.event; package com.github.games647.fastlogin.bungee.event;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSession; import com.github.games647.fastlogin.core.auth.LoginSession;
import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent; import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent;
import net.md_5.bungee.api.plugin.Cancellable; import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event; import net.md_5.bungee.api.plugin.Event;

View File

@ -1,7 +1,7 @@
package com.github.games647.fastlogin.bungee.event; package com.github.games647.fastlogin.bungee.event;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSource; import com.github.games647.fastlogin.core.auth.LoginSource;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent; import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import net.md_5.bungee.api.plugin.Event; import net.md_5.bungee.api.plugin.Event;

View File

@ -1,6 +1,6 @@
package com.github.games647.fastlogin.bungee.event; package com.github.games647.fastlogin.bungee.event;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent; import com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent;
import net.md_5.bungee.api.plugin.Event; import net.md_5.bungee.api.plugin.Event;

View File

@ -5,9 +5,9 @@ import com.github.games647.fastlogin.bungee.BungeeLoginSession;
import com.github.games647.fastlogin.bungee.FastLoginBungee; import com.github.games647.fastlogin.bungee.FastLoginBungee;
import com.github.games647.fastlogin.bungee.task.AsyncPremiumCheck; import com.github.games647.fastlogin.bungee.task.AsyncPremiumCheck;
import com.github.games647.fastlogin.bungee.task.ForceLoginTask; import com.github.games647.fastlogin.bungee.task.ForceLoginTask;
import com.github.games647.fastlogin.core.RateLimiter; import com.github.games647.fastlogin.core.auth.RateLimiter;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSession; import com.github.games647.fastlogin.core.auth.LoginSession;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
@ -31,6 +31,8 @@ import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority; import net.md_5.bungee.event.EventPriority;
import org.geysermc.floodgate.FloodgateAPI; import org.geysermc.floodgate.FloodgateAPI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Enables online mode logins for specified users and sends plugin message to the Bukkit version of this plugin in * Enables online mode logins for specified users and sends plugin message to the Bukkit version of this plugin in
@ -38,31 +40,41 @@ import org.geysermc.floodgate.FloodgateAPI;
*/ */
public class ConnectListener implements Listener { public class ConnectListener implements Listener {
private final FastLoginBungee plugin;
private final RateLimiter rateLimiter;
private final Property[] emptyProperties = {};
private final boolean floodGateAvailable;
private static final String UUID_FIELD_NAME = "uniqueId"; private static final String UUID_FIELD_NAME = "uniqueId";
private static final boolean initialHandlerClazzFound;
private static final MethodHandle uniqueIdSetter; private static final MethodHandle uniqueIdSetter;
static { static {
MethodHandle setHandle = null; MethodHandle setHandle = null;
boolean handlerFound = false;
try { try {
Lookup lookup = MethodHandles.lookup(); Lookup lookup = MethodHandles.lookup();
Class.forName("net.md_5.bungee.connection.InitialHandler");
handlerFound = true;
Field uuidField = InitialHandler.class.getDeclaredField(UUID_FIELD_NAME); Field uuidField = InitialHandler.class.getDeclaredField(UUID_FIELD_NAME);
uuidField.setAccessible(true); uuidField.setAccessible(true);
setHandle = lookup.unreflectSetter(uuidField); setHandle = lookup.unreflectSetter(uuidField);
} catch (ClassNotFoundException classNotFoundException) {
Logger logger = LoggerFactory.getLogger(ConnectListener.class);
logger.error(
"Cannot find Bungee initial handler; Disabling premium UUID and skin won't work.",
classNotFoundException
);
} catch (ReflectiveOperationException reflectiveOperationException) { } catch (ReflectiveOperationException reflectiveOperationException) {
reflectiveOperationException.printStackTrace(); reflectiveOperationException.printStackTrace();
} }
initialHandlerClazzFound = handlerFound;
uniqueIdSetter = setHandle; uniqueIdSetter = setHandle;
} }
private final FastLoginBungee plugin;
private final RateLimiter rateLimiter;
private final Property[] emptyProperties = {};
private final boolean floodGateAvailable;
public ConnectListener(FastLoginBungee plugin, RateLimiter rateLimiter, boolean floodgateAvailable) { public ConnectListener(FastLoginBungee plugin, RateLimiter rateLimiter, boolean floodgateAvailable) {
this.plugin = plugin; this.plugin = plugin;
this.rateLimiter = rateLimiter; this.rateLimiter = rateLimiter;
@ -71,22 +83,21 @@ public class ConnectListener implements Listener {
@EventHandler @EventHandler
public void onPreLogin(PreLoginEvent preLoginEvent) { public void onPreLogin(PreLoginEvent preLoginEvent) {
if (preLoginEvent.isCancelled() || isBedrockPlayer(preLoginEvent.getConnection().getUniqueId())) { PendingConnection connection = preLoginEvent.getConnection();
if (preLoginEvent.isCancelled() || isBedrockPlayer(connection.getUniqueId())) {
return; return;
} }
PendingConnection connection = preLoginEvent.getConnection();
if (!rateLimiter.tryAcquire()) { if (!rateLimiter.tryAcquire()) {
plugin.getLog().warn("Join limit hit - Ignoring player {}", connection); plugin.getLog().warn("Join limit hit - Ignoring player {}", connection);
return; return;
} }
InitialHandler initialHandler = (InitialHandler) connection; String username = connection.getName();
String username = initialHandler.getLoginRequest().getData(); plugin.getLog().info("Incoming login request for {} from {}", username, connection.getSocketAddress());
plugin.getLog().info("Incoming login request for {} from {}", username, initialHandler.getAddress());
preLoginEvent.registerIntent(plugin); preLoginEvent.registerIntent(plugin);
Runnable asyncPremiumCheck = new AsyncPremiumCheck(plugin, preLoginEvent, connection); Runnable asyncPremiumCheck = new AsyncPremiumCheck(plugin, preLoginEvent, connection, username);
plugin.getScheduler().runAsync(asyncPremiumCheck); plugin.getScheduler().runAsync(asyncPremiumCheck);
} }
@ -98,32 +109,34 @@ public class ConnectListener implements Listener {
//use the login event instead of the post login event in order to send the login success packet to the client //use the login event instead of the post login event in order to send the login success packet to the client
//with the offline uuid this makes it possible to set the skin then //with the offline uuid this makes it possible to set the skin then
final PendingConnection connection = loginEvent.getConnection(); PendingConnection connection = loginEvent.getConnection();
final InitialHandler initialHandler = (InitialHandler) connection;
if (connection.isOnlineMode()) { if (connection.isOnlineMode()) {
LoginSession session = plugin.getSession().get(connection); LoginSession session = plugin.getSession().get(connection);
LoginResult loginProfile = initialHandler.getLoginProfile();
UUID verifiedUUID = connection.getUniqueId(); UUID verifiedUUID = connection.getUniqueId();
String verifiedUsername = connection.getName();
session.setUuid(verifiedUUID); session.setUuid(verifiedUUID);
session.setVerifiedUsername(loginProfile.getName()); session.setVerifiedUsername(verifiedUsername);
StoredProfile playerProfile = session.getProfile(); StoredProfile playerProfile = session.getProfile();
playerProfile.setId(verifiedUUID); playerProfile.setId(verifiedUUID);
//bungeecord will do this automatically so override it on disabled option // bungeecord will do this automatically so override it on disabled option
if (uniqueIdSetter != null) {
InitialHandler initialHandler = (InitialHandler) connection;
if (!plugin.getCore().getConfig().get("premiumUuid", true)) { if (!plugin.getCore().getConfig().get("premiumUuid", true)) {
String username = loginProfile.getName(); setOfflineId(initialHandler, verifiedUsername);
setOfflineId(initialHandler, username);
} }
if (!plugin.getCore().getConfig().get("forwardSkin", true)) { if (!plugin.getCore().getConfig().get("forwardSkin", true)) {
// this is null on offline mode // this is null on offline mode
LoginResult loginProfile = initialHandler.getLoginProfile();
loginProfile.setProperties(emptyProperties); loginProfile.setProperties(emptyProperties);
} }
} }
} }
}
private void setOfflineId(InitialHandler connection, String username) { private void setOfflineId(InitialHandler connection, String username) {
try { try {

View File

@ -3,7 +3,7 @@ package com.github.games647.fastlogin.bungee.listener;
import com.github.games647.fastlogin.bungee.BungeeLoginSession; import com.github.games647.fastlogin.bungee.BungeeLoginSession;
import com.github.games647.fastlogin.bungee.FastLoginBungee; import com.github.games647.fastlogin.bungee.FastLoginBungee;
import com.github.games647.fastlogin.bungee.task.AsyncToggleMessage; import com.github.games647.fastlogin.bungee.task.AsyncToggleMessage;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.message.ChangePremiumMessage; import com.github.games647.fastlogin.core.message.ChangePremiumMessage;
import com.github.games647.fastlogin.core.message.NamespaceKey; import com.github.games647.fastlogin.core.message.NamespaceKey;
import com.github.games647.fastlogin.core.message.SuccessMessage; import com.github.games647.fastlogin.core.message.SuccessMessage;

View File

@ -4,15 +4,14 @@ import com.github.games647.fastlogin.bungee.BungeeLoginSession;
import com.github.games647.fastlogin.bungee.BungeeLoginSource; import com.github.games647.fastlogin.bungee.BungeeLoginSource;
import com.github.games647.fastlogin.bungee.FastLoginBungee; import com.github.games647.fastlogin.bungee.FastLoginBungee;
import com.github.games647.fastlogin.bungee.event.BungeeFastLoginPreLoginEvent; import com.github.games647.fastlogin.bungee.event.BungeeFastLoginPreLoginEvent;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.JoinManagement; import com.github.games647.fastlogin.core.auth.JoinManagement;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent; import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.PendingConnection; import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PreLoginEvent; import net.md_5.bungee.api.event.PreLoginEvent;
import net.md_5.bungee.connection.InitialHandler;
public class AsyncPremiumCheck extends JoinManagement<ProxiedPlayer, CommandSender, BungeeLoginSource> public class AsyncPremiumCheck extends JoinManagement<ProxiedPlayer, CommandSender, BungeeLoginSource>
implements Runnable { implements Runnable {
@ -20,22 +19,23 @@ public class AsyncPremiumCheck extends JoinManagement<ProxiedPlayer, CommandSend
private final FastLoginBungee plugin; private final FastLoginBungee plugin;
private final PreLoginEvent preLoginEvent; private final PreLoginEvent preLoginEvent;
private final String username;
private final PendingConnection connection; private final PendingConnection connection;
public AsyncPremiumCheck(FastLoginBungee plugin, PreLoginEvent preLoginEvent, PendingConnection connection) { public AsyncPremiumCheck(FastLoginBungee plugin, PreLoginEvent preLoginEvent, PendingConnection connection,
String username) {
super(plugin.getCore(), plugin.getCore().getAuthPluginHook()); super(plugin.getCore(), plugin.getCore().getAuthPluginHook());
this.plugin = plugin; this.plugin = plugin;
this.preLoginEvent = preLoginEvent; this.preLoginEvent = preLoginEvent;
this.connection = connection; this.connection = connection;
this.username = username;
} }
@Override @Override
public void run() { public void run() {
plugin.getSession().remove(connection); plugin.getSession().remove(connection);
InitialHandler initialHandler = (InitialHandler) connection;
String username = initialHandler.getLoginRequest().getData();
try { try {
super.onLogin(username, new BungeeLoginSource(connection, preLoginEvent)); super.onLogin(username, new BungeeLoginSource(connection, preLoginEvent));
} finally { } finally {

View File

@ -2,10 +2,9 @@ package com.github.games647.fastlogin.bungee.task;
import com.github.games647.fastlogin.bungee.FastLoginBungee; import com.github.games647.fastlogin.bungee.FastLoginBungee;
import com.github.games647.fastlogin.bungee.event.BungeeFastLoginPremiumToggleEvent; import com.github.games647.fastlogin.bungee.event.BungeeFastLoginPremiumToggleEvent;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.FastLoginCore; import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent;
import com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent.PremiumToggleReason; import com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent.PremiumToggleReason;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;

View File

@ -3,13 +3,13 @@ package com.github.games647.fastlogin.bungee.task;
import com.github.games647.fastlogin.bungee.BungeeLoginSession; import com.github.games647.fastlogin.bungee.BungeeLoginSession;
import com.github.games647.fastlogin.bungee.FastLoginBungee; import com.github.games647.fastlogin.bungee.FastLoginBungee;
import com.github.games647.fastlogin.bungee.event.BungeeFastLoginAutoLoginEvent; import com.github.games647.fastlogin.bungee.event.BungeeFastLoginAutoLoginEvent;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.message.ChannelMessage; import com.github.games647.fastlogin.core.message.ChannelMessage;
import com.github.games647.fastlogin.core.message.LoginActionMessage; import com.github.games647.fastlogin.core.message.LoginActionMessage;
import com.github.games647.fastlogin.core.message.LoginActionMessage.Type; import com.github.games647.fastlogin.core.message.LoginActionMessage.Type;
import com.github.games647.fastlogin.core.shared.FastLoginCore; import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.ForceLoginManagement; import com.github.games647.fastlogin.core.auth.ForceLoginManagement;
import com.github.games647.fastlogin.core.shared.LoginSession; import com.github.games647.fastlogin.core.auth.LoginSession;
import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent; import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent;
import java.util.UUID; import java.util.UUID;

View File

@ -0,0 +1,62 @@
package com.github.games647.fastlogin.core;
import com.github.games647.fastlogin.core.auth.LoginSession;
import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.google.common.collect.MapMaker;
import java.util.UUID;
import java.util.concurrent.ConcurrentMap;
/**
* Manages player connection sessions. Login sessions that are only valid through the login process and play
* sessions that hold the stored profile object after the login process is finished and until the player leaves the
* server (Spigot) or proxy (BungeeCord).
*
* @param <C> connection object
* @param <S> platform dependent login session
*/
public abstract class SessionManager<E, C, S extends LoginSession> {
// 1 minutes should be enough as a timeout for bad internet connection (Server, Client and Mojang)
// these login sessions are only meant for during the login process not be used after
private final ConcurrentMap<C, S> loginSessions = CommonUtil.buildCache(1, 0);
private final ConcurrentMap<UUID, StoredProfile> playSessions = new MapMaker().makeMap();
public void startLoginSession(C connectionId, S session) {
loginSessions.put(connectionId, session);
}
public S getLoginSession(C connectionId) {
return loginSessions.get(connectionId);
}
public void endLoginSession(C connectionId) {
loginSessions.remove(connectionId);
}
public ConcurrentMap<C, S> getLoginSessions() {
return loginSessions;
}
public S promoteSession(C connectionId, UUID playerId) {
S loginSession = loginSessions.remove(connectionId);
StoredProfile profile = loginSession.getProfile();
playSessions.put(playerId, profile);
return loginSession;
}
public StoredProfile getPlaySession(UUID playerId) {
return playSessions.get(playerId);
}
public void endPlaySession(UUID playerId) {
playSessions.remove(playerId);
}
public abstract void onPlayQuit(E quitEvent);
public void clear() {
loginSessions.clear();
playSessions.clear();
}
}

View File

@ -1,7 +1,9 @@
package com.github.games647.fastlogin.core.shared; package com.github.games647.fastlogin.core.auth;
import com.github.games647.fastlogin.core.AuthStorage; import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.shared.PlatformPlugin;
import com.github.games647.fastlogin.core.storage.AuthStorage;
import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.hooks.AuthPlugin; import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent; import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent;

View File

@ -1,8 +1,9 @@
package com.github.games647.fastlogin.core.shared; package com.github.games647.fastlogin.core.auth;
import com.github.games647.craftapi.model.Profile; import com.github.games647.craftapi.model.Profile;
import com.github.games647.craftapi.resolver.RateLimitException; import com.github.games647.craftapi.resolver.RateLimitException;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.hooks.AuthPlugin; import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent; import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;

View File

@ -1,6 +1,6 @@
package com.github.games647.fastlogin.core.shared; package com.github.games647.fastlogin.core.auth;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import java.util.UUID; import java.util.UUID;

View File

@ -1,4 +1,4 @@
package com.github.games647.fastlogin.core.shared; package com.github.games647.fastlogin.core.auth;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;

View File

@ -1,4 +1,4 @@
package com.github.games647.fastlogin.core; package com.github.games647.fastlogin.core.auth;
/** /**
* Limit the number of requests with a maximum size. Each requests expires after the specified time making it available * Limit the number of requests with a maximum size. Each requests expires after the specified time making it available

View File

@ -2,9 +2,9 @@ package com.github.games647.fastlogin.core.shared;
import com.github.games647.craftapi.resolver.MojangResolver; import com.github.games647.craftapi.resolver.MojangResolver;
import com.github.games647.craftapi.resolver.http.RotatingProxySelector; import com.github.games647.craftapi.resolver.http.RotatingProxySelector;
import com.github.games647.fastlogin.core.AuthStorage; import com.github.games647.fastlogin.core.storage.AuthStorage;
import com.github.games647.fastlogin.core.CommonUtil; import com.github.games647.fastlogin.core.CommonUtil;
import com.github.games647.fastlogin.core.RateLimiter; import com.github.games647.fastlogin.core.auth.RateLimiter;
import com.github.games647.fastlogin.core.hooks.AuthPlugin; import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.hooks.DefaultPasswordGenerator; import com.github.games647.fastlogin.core.hooks.DefaultPasswordGenerator;
import com.github.games647.fastlogin.core.hooks.PasswordGenerator; import com.github.games647.fastlogin.core.hooks.PasswordGenerator;
@ -90,7 +90,7 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
} }
int maxCon = config.getInt("anti-bot.connections", 200); int maxCon = config.getInt("anti-bot.connections", 200);
long expireTime = config.getInt("anti-bot.expire", 5) * 60 * 1_000L; long expireTime = config.getLong("anti-bot.expire", 5) * 60 * 1_000L;
if (expireTime > MAX_EXPIRE_RATE) { if (expireTime > MAX_EXPIRE_RATE) {
expireTime = MAX_EXPIRE_RATE; expireTime = MAX_EXPIRE_RATE;
} }
@ -132,7 +132,7 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
config = configProvider.load(reader, defaults); config = configProvider.load(reader, defaults);
} }
//explicitly add keys here, because Configuration.getKeys doesn't return the keys from the default configuration // explicitly add keys here, because Configuration.getKeys doesn't return the keys from the default configuration
for (String key : defaults.getKeys()) { for (String key : defaults.getKeys()) {
config.set(key, config.get(key)); config.set(key, config.get(key));
} }

View File

@ -1,9 +1,10 @@
package com.github.games647.fastlogin.core.shared.event; package com.github.games647.fastlogin.core.shared.event;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSession; import com.github.games647.fastlogin.core.auth.LoginSession;
public interface FastLoginAutoLoginEvent extends FastLoginCancellableEvent { public interface FastLoginAutoLoginEvent extends FastLoginCancellableEvent {
LoginSession getSession(); LoginSession getSession();
StoredProfile getProfile(); StoredProfile getProfile();
} }

View File

@ -3,5 +3,6 @@ package com.github.games647.fastlogin.core.shared.event;
public interface FastLoginCancellableEvent { public interface FastLoginCancellableEvent {
boolean isCancelled(); boolean isCancelled();
void setCancelled(boolean cancelled); void setCancelled(boolean cancelled);
} }

View File

@ -1,11 +1,13 @@
package com.github.games647.fastlogin.core.shared.event; package com.github.games647.fastlogin.core.shared.event;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSource; import com.github.games647.fastlogin.core.auth.LoginSource;
public interface FastLoginPreLoginEvent { public interface FastLoginPreLoginEvent {
String getUsername(); String getUsername();
LoginSource getSource(); LoginSource getSource();
StoredProfile getProfile(); StoredProfile getProfile();
} }

View File

@ -1,10 +1,11 @@
package com.github.games647.fastlogin.core.shared.event; package com.github.games647.fastlogin.core.shared.event;
import com.github.games647.fastlogin.core.StoredProfile; import com.github.games647.fastlogin.core.storage.StoredProfile;
public interface FastLoginPremiumToggleEvent { public interface FastLoginPremiumToggleEvent {
StoredProfile getProfile(); StoredProfile getProfile();
PremiumToggleReason getReason(); PremiumToggleReason getReason();
enum PremiumToggleReason { enum PremiumToggleReason {

View File

@ -1,4 +1,4 @@
package com.github.games647.fastlogin.core; package com.github.games647.fastlogin.core.storage;
import com.github.games647.craftapi.UUIDAdapter; import com.github.games647.craftapi.UUIDAdapter;
import com.github.games647.fastlogin.core.shared.FastLoginCore; import com.github.games647.fastlogin.core.shared.FastLoginCore;
@ -206,7 +206,7 @@ public class AuthStorage {
saveStmt.execute(); saveStmt.execute();
try (ResultSet generatedKeys = saveStmt.getGeneratedKeys()) { try (ResultSet generatedKeys = saveStmt.getGeneratedKeys()) {
if (generatedKeys != null && generatedKeys.next()) { if (generatedKeys.next()) {
playerProfile.setRowId(generatedKeys.getInt(1)); playerProfile.setRowId(generatedKeys.getInt(1));
} }
} }

View File

@ -1,8 +1,9 @@
package com.github.games647.fastlogin.core; package com.github.games647.fastlogin.core.storage;
import com.github.games647.craftapi.model.Profile; import com.github.games647.craftapi.model.Profile;
import java.time.Instant; import java.time.Instant;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
@ -86,6 +87,21 @@ public class StoredProfile extends Profile {
this.lastLogin = lastLogin; this.lastLogin = lastLogin;
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof StoredProfile)) return false;
if (!super.equals(o)) return false;
StoredProfile that = (StoredProfile) o;
return rowId == that.rowId && premium == that.premium
&& Objects.equals(lastIp, that.lastIp) && lastLogin.equals(that.lastLogin);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), rowId, premium, lastIp, lastLogin);
}
@Override @Override
public synchronized String toString() { public synchronized String toString() {
return this.getClass().getSimpleName() + '{' + return this.getClass().getSimpleName() + '{' +

View File

@ -85,14 +85,15 @@ premiumUuid: false
# player changed it's username and we just update the name in the database. # player changed it's username and we just update the name in the database.
# Examples: # Examples:
# #### Case 1 # #### Case 1
# nameChangeCheck = false ----- autoRegister = false # autoRegister = false
# nameChangeCheck = false
# #
# GameProfile logins as cracked until the player invoked the command /premium. Then we could override the existing # GameProfile logins as cracked until the player invoked the command /premium. Then we could override the existing
# database record. # database record.
# #
# #### Case 2 # #### Case 2
# # autoRegister = false
# nameChangeCheck = true ----- autoRegister = false # nameChangeCheck = true
# #
# Connect the Mojang API and check what UUID the player has (UUID exists => Paid Minecraft account). If that UUID is in # Connect the Mojang API and check what UUID the player has (UUID exists => Paid Minecraft account). If that UUID is in
# the database it's an **existing player** and FastLogin can **assume** the player is premium and changed the username. # the database it's an **existing player** and FastLogin can **assume** the player is premium and changed the username.
@ -104,8 +105,8 @@ premiumUuid: false
# in the meanwhile). # in the meanwhile).
# #
# #### Case 3 # #### Case 3
# # autoRegister = true
# nameChangeCheck = false ----- autoRegister = true # nameChangeCheck = false
# #
# We will always request a premium authentication if the username is unknown to us, but is in use by a paid Minecraft # We will always request a premium authentication if the username is unknown to us, but is in use by a paid Minecraft
# account. This means it's kind of a more aggressive check like nameChangeCheck = true and autoRegister = false, because # account. This means it's kind of a more aggressive check like nameChangeCheck = true and autoRegister = false, because
@ -114,8 +115,8 @@ premiumUuid: false
# **Limitation**: see below # **Limitation**: see below
# #
# #### Case 4 # #### Case 4
# # autoRegister = true
# nameChangeCheck = true ----- autoRegister = true # nameChangeCheck = true
# #
# Based on autoRegister it checks if the player name is premium and login using a premium authentication. After that # Based on autoRegister it checks if the player name is premium and login using a premium authentication. After that
# fastlogin receives the premium UUID and can update the database record. # fastlogin receives the premium UUID and can update the database record.

View File

@ -1,5 +1,7 @@
package com.github.games647.fastlogin.core; package com.github.games647.fastlogin.core;
import com.github.games647.fastlogin.core.auth.RateLimiter;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.junit.Test; import org.junit.Test;

View File

@ -52,7 +52,7 @@
<plugin> <plugin>
<groupId>pl.project13.maven</groupId> <groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId> <artifactId>git-commit-id-plugin</artifactId>
<version>4.0.0</version> <version>4.0.3</version>
<configuration> <configuration>
<failOnNoGitDirectory>false</failOnNoGitDirectory> <failOnNoGitDirectory>false</failOnNoGitDirectory>
</configuration> </configuration>