diff --git a/.gitignore b/.gitignore index be7173a9..6bbc48a8 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,4 @@ gradle-app.setting bukkit/target universal/target bungee/target -core/target \ No newline at end of file +core/target diff --git a/CHANGELOG.md b/CHANGELOG.md index 02294fe7..9240b11e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +######1.4 + +* Added Bungee setAuthPlugin method +* Multiple BungeeCord support + ######1.3.1 * Prevent thread create violation in BungeeCord @@ -127,4 +132,4 @@ * Added better error handling #####0.1 -* First release \ No newline at end of file +* First release diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitCore.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitCore.java index 318a68d2..3304694d 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitCore.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitCore.java @@ -1,15 +1,10 @@ package com.github.games647.fastlogin.bukkit; -import com.comphenix.protocol.utility.SafeCacheBuilder; import com.github.games647.fastlogin.core.FastLoginCore; -import com.github.games647.fastlogin.core.PlayerProfile; -import com.google.common.cache.CacheLoader; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.io.File; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; import java.util.logging.Logger; public class BukkitCore extends FastLoginCore { @@ -30,21 +25,6 @@ public class BukkitCore extends FastLoginCore { return plugin.getLogger(); } - @Override - public ConcurrentMap buildCache() { - return SafeCacheBuilder - .newBuilder() - .concurrencyLevel(20) - .expireAfterAccess(30, TimeUnit.MINUTES) - .build(new CacheLoader() { - @Override - public PlayerProfile load(String key) throws Exception { - //should be fetched manually - throw new UnsupportedOperationException("Not supported yet."); - } - }); - } - @Override public ThreadFactory getThreadFactory() { String pluginName = plugin.getName(); diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/PlayerSession.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java similarity index 68% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/PlayerSession.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java index 6c95407f..999448a4 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/PlayerSession.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java @@ -1,6 +1,8 @@ package com.github.games647.fastlogin.bukkit; import com.comphenix.protocol.wrappers.WrappedSignedProperty; +import com.github.games647.fastlogin.core.LoginSession; +import com.github.games647.fastlogin.core.PlayerProfile; import java.util.UUID; @@ -11,33 +13,32 @@ import org.apache.commons.lang.ArrayUtils; * * This session is invalid if the player disconnects or the login was successful */ -public class PlayerSession { +public class BukkitLoginSession extends LoginSession { - private final String username; private final String serverId; private final byte[] verifyToken; private UUID uuid; private WrappedSignedProperty skinProperty; private boolean verified; - private boolean registered; - public PlayerSession(String username, String serverId, byte[] verifyToken) { - this.username = username; + public BukkitLoginSession(String username, String serverId, byte[] verifyToken, boolean registered + , PlayerProfile profile) { + super(username, registered, profile); + this.serverId = serverId; this.verifyToken = ArrayUtils.clone(verifyToken); } - public PlayerSession(String username) { - this(username, "", ArrayUtils.EMPTY_BYTE_ARRAY); + //available for bungeecord + public BukkitLoginSession(String username, boolean registered) { + this(username, "", ArrayUtils.EMPTY_BYTE_ARRAY, registered, null); } /** - * Gets the random generated server id. This makes sure the request - * sent from the client is just for this server. + * Gets the random generated server id. This makes sure the request sent from the client is just for this server. * - * See this for details - * http://www.sk89q.com/2011/09/minecraft-name-spoofing-exploit/ + * See this for details http://www.sk89q.com/2011/09/minecraft-name-spoofing-exploit/ * * Empty if it's a BungeeCord connection * @@ -58,15 +59,6 @@ public class PlayerSession { return ArrayUtils.clone(verifyToken); } - /** - * Gets the username the player sent to the server - * - * @return the client sent username - */ - public String getUsername() { - return username; - } - /** * Gets the premium skin of this player * @@ -86,26 +78,7 @@ public class PlayerSession { } /** - * Sets whether the account of this player already exists - * - * @param registered whether the account exists - */ - public synchronized void setRegistered(boolean registered) { - this.registered = registered; - } - - /** - * Gets whether the account of this player already exists. - * - * @return whether the account exists - */ - public synchronized boolean needsRegistration() { - return !registered; - } - - /** - * Sets whether the player has a premium (paid account) account - * and valid session + * Sets whether the player has a premium (paid account) account and valid session * * @param verified whether the player has valid session */ @@ -122,7 +95,6 @@ public class PlayerSession { return uuid; } - /** * Set the online UUID if it's fetched * @@ -133,8 +105,7 @@ public class PlayerSession { } /** - * Get whether the player has a premium (paid account) account - * and valid session + * Get whether the player has a premium (paid account) account and valid session * * @return whether the player has a valid session */ diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java index 1c9c383d..b2f05eba 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java @@ -40,14 +40,14 @@ public class FastLoginBukkit extends JavaPlugin { //this map is thread-safe for async access (Packet Listener) //SafeCacheBuilder is used in order to be version independent - private final ConcurrentMap session = SafeCacheBuilder.newBuilder() + private final ConcurrentMap session = SafeCacheBuilder.newBuilder() //2 minutes should be enough as a timeout for bad internet connection (Server, Client and Mojang) .expireAfterWrite(1, TimeUnit.MINUTES) //mapped by ip:port -> PlayerSession - .build(new CacheLoader() { + .build(new CacheLoader() { @Override - public PlayerSession load(String key) throws Exception { + public BukkitLoginSession load(String key) throws Exception { //A key should be inserted manually on start packet throw new UnsupportedOperationException("Not supported"); } @@ -158,7 +158,7 @@ public class FastLoginBukkit extends JavaPlugin { * * @return a thread-safe session map */ - public ConcurrentMap getSessions() { + public ConcurrentMap getSessions() { return session; } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/ForceLoginTask.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/ForceLoginTask.java index d5c0b86a..3c1601a1 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/ForceLoginTask.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/ForceLoginTask.java @@ -17,7 +17,7 @@ import org.bukkit.entity.Player; public class ForceLoginTask implements Runnable { - protected final FastLoginBukkit plugin; + private final FastLoginBukkit plugin; protected final Player player; public ForceLoginTask(FastLoginBukkit plugin, Player player) { @@ -33,14 +33,12 @@ public class ForceLoginTask implements Runnable { //remove the bungeecord identifier if there is ones String id = '/' + player.getAddress().getAddress().getHostAddress() + ':' + player.getAddress().getPort(); - PlayerSession session = plugin.getSessions().get(id); - - BukkitAuthPlugin authPlugin = plugin.getAuthPlugin(); + BukkitLoginSession session = plugin.getSessions().remove(id); Storage storage = plugin.getCore().getStorage(); PlayerProfile playerProfile = null; - if (storage != null) { - playerProfile = storage.getProfile(player.getName(), false); + if (session != null) { + playerProfile = session.getProfile(); } if (session == null) { @@ -53,6 +51,7 @@ public class ForceLoginTask implements Runnable { //check if it's the same player as we checked before } else if (player.getName().equals(session.getUsername())) { //premium player + BukkitAuthPlugin authPlugin = plugin.getAuthPlugin(); if (authPlugin == null) { //maybe only bungeecord plugin sendSuccessNotification(); diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java index c1e4873d..c3a99e12 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java @@ -25,11 +25,11 @@ public class MojangApiBukkit extends MojangApiConnector { @Override public boolean hasJoinedServer(Object session, String serverId) { - if (!(session instanceof PlayerSession)) { + if (!(session instanceof BukkitLoginSession)) { return false; } - PlayerSession playerSession = (PlayerSession) session; + BukkitLoginSession playerSession = (BukkitLoginSession) session; try { String url = HAS_JOINED_URL + "username=" + playerSession.getUsername() + "&serverId=" + serverId; HttpURLConnection conn = getConnection(url); diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/CrackedCommand.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/CrackedCommand.java index 9f93c148..fb675035 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/CrackedCommand.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/CrackedCommand.java @@ -34,7 +34,7 @@ public class CrackedCommand implements CommandExecutor { sender.sendMessage(ChatColor.YELLOW + "Sending request..."); } else { //todo: load async if it's not in the cache anymore - final PlayerProfile profile = plugin.getCore().getStorage().getProfile(sender.getName(), true); + final PlayerProfile profile = plugin.getCore().getStorage().loadProfile(sender.getName()); if (profile.isPremium()) { sender.sendMessage(ChatColor.DARK_GREEN + "Removed from the list of premium players"); profile.setPremium(false); @@ -62,7 +62,7 @@ public class CrackedCommand implements CommandExecutor { sender.sendMessage(ChatColor.YELLOW + "Sending request for player " + args[0] + "..."); } else { //todo: load async if it's not in the cache anymore - final PlayerProfile profile = plugin.getCore().getStorage().getProfile(args[0], true); + final PlayerProfile profile = plugin.getCore().getStorage().loadProfile(args[0]); if (profile == null) { sender.sendMessage(ChatColor.DARK_RED + "Player not in the database"); return true; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/PremiumCommand.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/PremiumCommand.java index a25234a0..e37df3b9 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/PremiumCommand.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/PremiumCommand.java @@ -39,7 +39,7 @@ public class PremiumCommand implements CommandExecutor { sender.sendMessage(ChatColor.YELLOW + "Sending request..."); } else { // //todo: load async if it's not in the cache anymore - final PlayerProfile profile = plugin.getCore().getStorage().getProfile(sender.getName(), true); + final PlayerProfile profile = plugin.getCore().getStorage().loadProfile(sender.getName()); if (profile.isPremium()) { sender.sendMessage(ChatColor.DARK_RED + "You are already on the premium list"); } else { @@ -68,7 +68,7 @@ public class PremiumCommand implements CommandExecutor { sender.sendMessage(ChatColor.YELLOW + "Sending request..."); } else { //todo: load async if it's not in the cache anymore - final PlayerProfile profile = plugin.getCore().getStorage().getProfile(args[0], true); + final PlayerProfile profile = plugin.getCore().getStorage().loadProfile(args[0]); if (profile == null) { sender.sendMessage(ChatColor.DARK_RED + "Player not in the database"); return true; diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BukkitJoinListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BukkitJoinListener.java index e83c7138..c5a26343 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BukkitJoinListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BukkitJoinListener.java @@ -4,7 +4,7 @@ import com.comphenix.protocol.wrappers.WrappedGameProfile; import com.comphenix.protocol.wrappers.WrappedSignedProperty; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.bukkit.ForceLoginTask; -import com.github.games647.fastlogin.bukkit.PlayerSession; +import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -14,7 +14,6 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent.Result; -import org.bukkit.event.player.PlayerQuitEvent; /** * This listener tells authentication plugins if the player has a premium account and we checked it successfully. So the @@ -41,7 +40,7 @@ public class BukkitJoinListener implements Listener { public void onPlayerJoin(PlayerJoinEvent joinEvent) { Player player = joinEvent.getPlayer(); - PlayerSession session = plugin.getSessions().get(player.getAddress().toString()); + BukkitLoginSession session = plugin.getSessions().get(player.getAddress().toString()); if (session != null && plugin.getConfig().getBoolean("forwardSkin")) { WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(player); WrappedSignedProperty skin = session.getSkin(); @@ -55,12 +54,4 @@ public class BukkitJoinListener implements Listener { Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, new ForceLoginTask(plugin, player), DELAY_LOGIN); } } - - @EventHandler - public void onPlayerQuit(PlayerQuitEvent quitEvent) { - Player player = quitEvent.getPlayer(); - - //prevent memory leaks - player.removeMetadata(plugin.getName(), plugin); - } } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeCordListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeCordListener.java index 86d89813..af46e02b 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeCordListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeCordListener.java @@ -2,15 +2,18 @@ package com.github.games647.fastlogin.bukkit.listener; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.bukkit.ForceLoginTask; -import com.github.games647.fastlogin.bukkit.PlayerSession; +import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.hooks.BukkitAuthPlugin; import com.google.common.base.Charsets; +import com.google.common.collect.Sets; import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteStreams; import com.google.common.io.Files; import java.io.File; import java.io.IOException; +import java.util.List; +import java.util.Set; import java.util.UUID; import java.util.logging.Level; @@ -31,11 +34,11 @@ public class BungeeCordListener implements PluginMessageListener { protected final FastLoginBukkit plugin; //null if whitelist is empty so bungeecord support is disabled - private final UUID proxyId; + private final Set proxyIds; public BungeeCordListener(FastLoginBukkit plugin) { this.plugin = plugin; - this.proxyId = loadBungeeCordId(); + this.proxyIds = loadBungeeCordIds(); } @Override @@ -65,17 +68,14 @@ public class BungeeCordListener implements PluginMessageListener { plugin.getLogger().log(Level.FINEST, "Received proxy id {0} from {1}", new Object[]{sourceId, player}); //fail if BungeeCord support is disabled (id = null) - if (sourceId.equals(proxyId)) { - final PlayerSession playerSession = new PlayerSession(playerName); + if (proxyIds.contains(sourceId)) { final String id = '/' + checkedPlayer.getAddress().getAddress().getHostAddress() + ':' + checkedPlayer.getAddress().getPort(); if ("AUTO_LOGIN".equalsIgnoreCase(subchannel)) { + BukkitLoginSession playerSession = new BukkitLoginSession(playerName, true); playerSession.setVerified(true); - playerSession.setRegistered(true); plugin.getSessions().put(id, playerSession); } else if ("AUTO_REGISTER".equalsIgnoreCase(subchannel)) { - playerSession.setVerified(true); - Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { @Override public void run() { @@ -83,6 +83,8 @@ public class BungeeCordListener implements PluginMessageListener { try { //we need to check if the player is registered on Bukkit too if (authPlugin != null && !authPlugin.isRegistered(playerName)) { + BukkitLoginSession playerSession = new BukkitLoginSession(playerName, false); + playerSession.setVerified(true); plugin.getSessions().put(id, playerSession); } } catch (Exception ex) { @@ -97,7 +99,7 @@ public class BungeeCordListener implements PluginMessageListener { } } - public UUID loadBungeeCordId() { + public Set loadBungeeCordIds() { File whitelistFile = new File(plugin.getDataFolder(), FILE_NAME); //create a new folder if it doesn't exist. Fail silently otherwise whitelistFile.getParentFile().mkdir(); @@ -106,9 +108,16 @@ public class BungeeCordListener implements PluginMessageListener { whitelistFile.createNewFile(); } - String firstLine = Files.readFirstLine(whitelistFile, Charsets.UTF_8); - if (firstLine != null && !firstLine.isEmpty()) { - return UUID.fromString(firstLine.trim()); + Set ids = Sets.newHashSet(); + + List lines = Files.readLines(whitelistFile, Charsets.UTF_8); + for (String line : lines) { + if (line == null || line.trim().isEmpty()) { + continue; + } + + UUID uuid = UUID.fromString(line.trim()); + ids.add(uuid); } } catch (IOException ex) { plugin.getLogger().log(Level.SEVERE, "Failed to create file for Proxy whitelist", ex); diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ProtocolSupportListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ProtocolSupportListener.java index 8a39fab1..532d5089 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ProtocolSupportListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ProtocolSupportListener.java @@ -1,7 +1,7 @@ package com.github.games647.fastlogin.bukkit.listener; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.bukkit.PlayerSession; +import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.hooks.BukkitAuthPlugin; import com.github.games647.fastlogin.core.PlayerProfile; @@ -33,18 +33,18 @@ public class ProtocolSupportListener implements Listener { String username = loginStartEvent.getName(); //remove old data every time on a new login in order to keep the session only for one person - plugin.getSessions().remove(username); + plugin.getSessions().remove(loginStartEvent.getAddress().toString()); BukkitAuthPlugin authPlugin = plugin.getAuthPlugin(); if (authPlugin == null) { return; } - PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(username, true); + PlayerProfile playerProfile = plugin.getCore().getStorage().loadProfile(username); if (playerProfile != null) { if (playerProfile.isPremium()) { if (playerProfile.getUserId() != -1) { - startPremiumSession(username, loginStartEvent, true); + startPremiumSession(username, loginStartEvent, true, playerProfile); } } else if (playerProfile.getUserId() == -1) { //user not exists in the db @@ -53,7 +53,7 @@ public class ProtocolSupportListener implements Listener { UUID premiumUUID = plugin.getCore().getMojangApiConnector().getPremiumUUID(username); if (premiumUUID != null) { plugin.getLogger().log(Level.FINER, "Player {0} uses a premium username", username); - startPremiumSession(username, loginStartEvent, false); + startPremiumSession(username, loginStartEvent, false, playerProfile); } } } catch (Exception ex) { @@ -68,19 +68,19 @@ public class ProtocolSupportListener implements Listener { //skin was resolved -> premium player if (propertiesResolveEvent.hasProperty("textures")) { InetSocketAddress address = propertiesResolveEvent.getAddress(); - PlayerSession session = plugin.getSessions().get(address.toString()); + BukkitLoginSession session = plugin.getSessions().get(address.toString()); if (session != null) { session.setVerified(true); } } } - private void startPremiumSession(String playerName, PlayerLoginStartEvent loginStartEvent, boolean registered) { + private void startPremiumSession(String playerName, PlayerLoginStartEvent loginStartEvent, boolean registered + , PlayerProfile playerProfile) { loginStartEvent.setOnlineMode(true); InetSocketAddress address = loginStartEvent.getAddress(); - PlayerSession playerSession = new PlayerSession(playerName, null, null); - playerSession.setRegistered(registered); + BukkitLoginSession playerSession = new BukkitLoginSession(playerName, null, null, registered, playerProfile); plugin.getSessions().put(address.toString(), playerSession); if (plugin.getConfig().getBoolean("premiumUuid")) { loginStartEvent.setUseOnlineModeUUID(true); diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/EncryptionPacketListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/EncryptionPacketListener.java index b1cabb94..2020786c 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/EncryptionPacketListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/EncryptionPacketListener.java @@ -11,7 +11,7 @@ import com.comphenix.protocol.wrappers.WrappedChatComponent; import com.comphenix.protocol.wrappers.WrappedGameProfile; import com.github.games647.fastlogin.bukkit.EncryptionUtil; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.bukkit.PlayerSession; +import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -73,13 +73,10 @@ public class EncryptionPacketListener extends PacketAdapter { public void onPacketReceiving(PacketEvent packetEvent) { Player player = packetEvent.getPlayer(); - //the player name is unknown to ProtocolLib (so getName() doesn't work) - now uses ip:port as key - String uniqueSessionKey = player.getAddress().toString(); - PlayerSession session = plugin.getSessions().get(uniqueSessionKey); + BukkitLoginSession session = plugin.getSessions().get(player.getAddress().toString()); if (session == null) { disconnect(packetEvent, "Invalid request", Level.FINE - , "Player {0} tried to send encryption response at invalid state" - , player.getAddress()); + , "Player {0} tried to send encryption response at invalid state", player.getAddress()); return; } @@ -118,7 +115,7 @@ public class EncryptionPacketListener extends PacketAdapter { packetEvent.setCancelled(true); } - private void setPremiumUUID(PlayerSession session, Player player) { + private void setPremiumUUID(BukkitLoginSession session, Player player) { UUID uuid = session.getUuid(); if (plugin.getConfig().getBoolean("premiumUuid") && uuid != null) { try { @@ -132,7 +129,7 @@ public class EncryptionPacketListener extends PacketAdapter { } } - private boolean checkVerifyToken(PlayerSession session, PrivateKey privateKey, PacketEvent packetEvent) { + private boolean checkVerifyToken(BukkitLoginSession session, PrivateKey privateKey, PacketEvent packetEvent) { byte[] requestVerify = session.getVerifyToken(); //encrypted verify token byte[] responseVerify = packetEvent.getPacket().getByteArrays().read(1); diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/StartPacketListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/StartPacketListener.java index 03b8bb03..41b5d711 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/StartPacketListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/StartPacketListener.java @@ -6,9 +6,9 @@ import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.core.PlayerProfile; -import com.github.games647.fastlogin.bukkit.PlayerSession; +import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.hooks.BukkitAuthPlugin; +import com.github.games647.fastlogin.core.PlayerProfile; import java.lang.reflect.InvocationTargetException; import java.security.PublicKey; @@ -83,20 +83,20 @@ public class StartPacketListener extends PacketAdapter { return; } - PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(username, true); - if (playerProfile != null) { - if (playerProfile.isPremium()) { - if (playerProfile.getUserId() != -1) { - enablePremiumLogin(username, sessionKey, player, packetEvent, true); + PlayerProfile profile = plugin.getCore().getStorage().loadProfile(username); + if (profile != null) { + if (profile.isPremium()) { + if (profile.getUserId() != -1) { + enablePremiumLogin(username, profile, sessionKey, player, packetEvent, true); } - } else if (playerProfile.getUserId() == -1) { + } else if (profile.getUserId() == -1) { //user not exists in the db try { if (plugin.getConfig().getBoolean("autoRegister") && !authPlugin.isRegistered(username)) { UUID premiumUUID = plugin.getCore().getMojangApiConnector().getPremiumUUID(username); if (premiumUUID != null) { plugin.getLogger().log(Level.FINER, "Player {0} uses a premium username", username); - enablePremiumLogin(username, sessionKey, player, packetEvent, false); + enablePremiumLogin(username, profile, sessionKey, player, packetEvent, false); } } } catch (Exception ex) { @@ -108,8 +108,8 @@ public class StartPacketListener extends PacketAdapter { //minecraft server implementation //https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L161 - private void enablePremiumLogin(String username, String sessionKey, Player player, PacketEvent packetEvent - , boolean registered) { + private void enablePremiumLogin(String username, PlayerProfile profile, String sessionKey, Player player + , PacketEvent packetEvent, boolean registered) { //randomized server id to make sure the request is for our server //this could be relevant http://www.sk89q.com/2011/09/minecraft-name-spoofing-exploit/ String serverId = Long.toString(random.nextLong(), 16); @@ -120,8 +120,8 @@ public class StartPacketListener extends PacketAdapter { boolean success = sentEncryptionRequest(player, serverId, verifyToken); if (success) { - PlayerSession playerSession = new PlayerSession(username, serverId, verifyToken); - playerSession.setRegistered(registered); + BukkitLoginSession playerSession = new BukkitLoginSession(username, serverId + , verifyToken, registered, profile); plugin.getSessions().put(sessionKey, playerSession); //cancel only if the player has a paid account otherwise login as normal offline player packetEvent.setCancelled(true); diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/AsyncPremiumCheck.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/AsyncPremiumCheck.java index 2bff5fa4..a0662eb0 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/AsyncPremiumCheck.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/AsyncPremiumCheck.java @@ -2,9 +2,12 @@ package com.github.games647.fastlogin.bungee; import com.github.games647.fastlogin.bungee.FastLoginBungee; import com.github.games647.fastlogin.bungee.hooks.BungeeAuthPlugin; +import com.github.games647.fastlogin.core.LoginSession; import com.github.games647.fastlogin.core.PlayerProfile; + import java.util.UUID; import java.util.logging.Level; + import net.md_5.bungee.api.connection.PendingConnection; import net.md_5.bungee.api.event.PreLoginEvent; @@ -21,15 +24,18 @@ public class AsyncPremiumCheck implements Runnable { @Override public void run() { PendingConnection connection = preLoginEvent.getConnection(); + plugin.getSession().remove(connection); + String username = connection.getName(); try { - PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(username, true); - if (playerProfile != null) { - if (playerProfile.isPremium()) { - if (playerProfile.getUserId() != -1) { + PlayerProfile profile = plugin.getCore().getStorage().loadProfile(username); + if (profile != null) { + if (profile.isPremium()) { + if (profile.getUserId() != -1) { + plugin.getSession().put(connection, new LoginSession(username, true, profile)); connection.setOnlineMode(true); } - } else if (playerProfile.getUserId() == -1) { + } else if (profile.getUserId() == -1) { //user not exists in the db BungeeAuthPlugin authPlugin = plugin.getBungeeAuthPlugin(); if (plugin.getConfiguration().getBoolean("autoRegister") @@ -38,7 +44,7 @@ public class AsyncPremiumCheck implements Runnable { if (premiumUUID != null) { plugin.getLogger().log(Level.FINER, "Player {0} uses a premium username", username); connection.setOnlineMode(true); - plugin.getPendingAutoRegister().put(connection, new Object()); + plugin.getSession().put(connection, new LoginSession(username, false, profile)); } } } diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/BungeeCore.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/BungeeCore.java index 7e7719d3..d0a8d83b 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/BungeeCore.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/BungeeCore.java @@ -1,14 +1,10 @@ package com.github.games647.fastlogin.bungee; import com.github.games647.fastlogin.core.FastLoginCore; -import com.github.games647.fastlogin.core.PlayerProfile; -import com.google.common.cache.CacheBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.io.File; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; import java.util.logging.Logger; import net.md_5.bungee.api.scheduler.GroupedThreadFactory; @@ -31,15 +27,6 @@ public class BungeeCore extends FastLoginCore { return plugin.getLogger(); } - @Override - public ConcurrentMap buildCache() { - return CacheBuilder - .newBuilder() - .concurrencyLevel(20) - .expireAfterAccess(30, TimeUnit.MINUTES) - .build().asMap(); - } - @Override public ThreadFactory getThreadFactory() { String pluginName = plugin.getDescription().getName(); diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/FastLoginBungee.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/FastLoginBungee.java index 4f8c0543..f04ffdef 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/FastLoginBungee.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/FastLoginBungee.java @@ -5,6 +5,7 @@ import com.github.games647.fastlogin.bungee.hooks.BungeeAuthPlugin; import com.github.games647.fastlogin.bungee.listener.PlayerConnectionListener; import com.github.games647.fastlogin.bungee.listener.PluginMessageListener; import com.github.games647.fastlogin.core.FastLoginCore; +import com.github.games647.fastlogin.core.LoginSession; import com.google.common.cache.CacheBuilder; import java.io.File; @@ -41,6 +42,11 @@ public class FastLoginBungee extends Plugin { .expireAfterWrite(1, TimeUnit.MINUTES) .build().asMap(); + private final ConcurrentMap session = CacheBuilder + .newBuilder() + .expireAfterWrite(1, TimeUnit.MINUTES) + .build().asMap(); + @Override public void onEnable() { loginCore.setMojangApiConnector(new MojangApiBungee(loginCore)); @@ -112,8 +118,8 @@ public class FastLoginBungee extends Plugin { return configuration; } - public ConcurrentMap getPendingAutoRegister() { - return pendingAutoRegister; + public ConcurrentMap getSession() { + return session; } /** diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/ForceLoginTask.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/ForceLoginTask.java index 2f619003..6eed0d3f 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/ForceLoginTask.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/ForceLoginTask.java @@ -1,11 +1,13 @@ package com.github.games647.fastlogin.bungee; -import com.github.games647.fastlogin.core.PlayerProfile; import com.github.games647.fastlogin.bungee.hooks.BungeeAuthPlugin; +import com.github.games647.fastlogin.core.LoginSession; +import com.github.games647.fastlogin.core.PlayerProfile; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; 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.connection.Server; @@ -24,17 +26,19 @@ public class ForceLoginTask implements Runnable { @Override public void run() { - PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(player.getName(), false); + PendingConnection pendingConnection = player.getPendingConnection(); + LoginSession session = plugin.getSession().remove(pendingConnection); + PlayerProfile playerProfile = session.getProfile(); //force login only on success - if (player.getPendingConnection().isOnlineMode()) { - boolean autoRegister = plugin.getPendingAutoRegister().remove(player.getPendingConnection()) != null; + if (pendingConnection.isOnlineMode()) { + boolean autoRegister = session.needsRegistration(); BungeeAuthPlugin authPlugin = plugin.getBungeeAuthPlugin(); if (authPlugin == null) { sendBukkitLoginNotification(autoRegister); } else if (player.isConnected()) { - if (autoRegister) { + if (session.needsRegistration()) { String password = plugin.generateStringPassword(); if (authPlugin.forceRegister(player, password)) { sendBukkitLoginNotification(autoRegister); diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/AsyncStatusMessage.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/AsyncStatusMessage.java index 6ee6726c..3a5d36bf 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/AsyncStatusMessage.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/AsyncStatusMessage.java @@ -14,7 +14,8 @@ public class AsyncStatusMessage implements Runnable { private final String targetPlayer; private final boolean toPremium; - public AsyncStatusMessage(FastLoginBungee plugin, ProxiedPlayer fromPlayer, String targetPlayer, boolean toPremium) { + public AsyncStatusMessage(FastLoginBungee plugin, ProxiedPlayer fromPlayer, String targetPlayer + , boolean toPremium) { this.plugin = plugin; this.fromPlayer = fromPlayer; this.targetPlayer = targetPlayer; @@ -31,7 +32,7 @@ public class AsyncStatusMessage implements Runnable { } private void turnOffPremium() { - PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(targetPlayer, true); + PlayerProfile playerProfile = plugin.getCore().getStorage().loadProfile(targetPlayer); if (!playerProfile.isPremium()) { if (fromPlayer.isConnected()) { TextComponent textComponent = new TextComponent("You are not in the premium list"); @@ -51,7 +52,7 @@ public class AsyncStatusMessage implements Runnable { } private void activatePremium() { - PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(targetPlayer, true); + PlayerProfile playerProfile = plugin.getCore().getStorage().loadProfile(targetPlayer); if (playerProfile.isPremium()) { if (fromPlayer.isConnected()) { TextComponent textComponent = new TextComponent("You are already on the premium list"); @@ -63,7 +64,6 @@ public class AsyncStatusMessage implements Runnable { } playerProfile.setPremium(true); - //todo: set uuid plugin.getCore().getStorage().save(playerProfile); TextComponent textComponent = new TextComponent("Added to the list of premium players"); textComponent.setColor(ChatColor.DARK_GREEN); diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java index 3f0e9c0b..456a7c1b 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java @@ -3,6 +3,7 @@ package com.github.games647.fastlogin.bungee.listener; import com.github.games647.fastlogin.bungee.AsyncPremiumCheck; import com.github.games647.fastlogin.bungee.FastLoginBungee; import com.github.games647.fastlogin.bungee.ForceLoginTask; +import com.github.games647.fastlogin.core.LoginSession; import com.github.games647.fastlogin.core.PlayerProfile; import com.google.common.base.Charsets; @@ -51,7 +52,8 @@ public class PlayerConnectionListener implements Listener { PendingConnection connection = player.getPendingConnection(); String username = connection.getName(); if (connection.isOnlineMode()) { - PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(player.getName(), false); + LoginSession session = plugin.getSession().get(connection); + PlayerProfile playerProfile = session.getProfile(); playerProfile.setUuid(player.getUniqueId()); //bungeecord will do this automatically so override it on disabled option diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PluginMessageListener.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PluginMessageListener.java index e8989729..17f34c88 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PluginMessageListener.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PluginMessageListener.java @@ -57,7 +57,7 @@ public class PluginMessageListener implements Listener { if (fromPlayer.getPendingConnection().isOnlineMode()) { //bukkit module successfully received and force logged in the user //update only on success to prevent corrupt data - PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(fromPlayer.getName(), false); + PlayerProfile playerProfile = plugin.getCore().getStorage().loadProfile(fromPlayer.getName()); playerProfile.setPremium(true); //we override this in the loginevent plugin.getCore().getStorage().save(playerProfile); diff --git a/core/src/main/java/com/github/games647/fastlogin/core/FastLoginCore.java b/core/src/main/java/com/github/games647/fastlogin/core/FastLoginCore.java index 9b595139..c3bb5884 100644 --- a/core/src/main/java/com/github/games647/fastlogin/core/FastLoginCore.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/FastLoginCore.java @@ -2,7 +2,6 @@ package com.github.games647.fastlogin.core; import java.io.File; import java.util.UUID; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ThreadFactory; import java.util.logging.Level; import java.util.logging.Logger; @@ -36,8 +35,6 @@ public abstract class FastLoginCore { public abstract Logger getLogger(); - public abstract ConcurrentMap buildCache(); - public abstract ThreadFactory getThreadFactory(); public boolean setupDatabase(String driver, String host, int port, String database, String user, String password) { diff --git a/core/src/main/java/com/github/games647/fastlogin/core/LoginSession.java b/core/src/main/java/com/github/games647/fastlogin/core/LoginSession.java new file mode 100644 index 00000000..6cac8cf5 --- /dev/null +++ b/core/src/main/java/com/github/games647/fastlogin/core/LoginSession.java @@ -0,0 +1,26 @@ +package com.github.games647.fastlogin.core; + +public class LoginSession { + + private final String username; + private final boolean registered; + private final PlayerProfile profile; + + public LoginSession(String username, boolean registered, PlayerProfile profile) { + this.username = username; + this.registered = registered; + this.profile = profile; + } + + public String getUsername() { + return username; + } + + public boolean needsRegistration() { + return !registered; + } + + public PlayerProfile getProfile() { + return profile; + } +} diff --git a/core/src/main/java/com/github/games647/fastlogin/core/Storage.java b/core/src/main/java/com/github/games647/fastlogin/core/Storage.java index b14d0c48..aa97b5ef 100644 --- a/core/src/main/java/com/github/games647/fastlogin/core/Storage.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/Storage.java @@ -9,7 +9,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.UUID; -import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; public class Storage { @@ -17,13 +16,11 @@ public class Storage { private static final String PREMIUM_TABLE = "premium"; private final FastLoginCore core; - private final ConcurrentMap profileCache; private final HikariDataSource dataSource; public Storage(FastLoginCore core, String driver, String host, int port, String databasePath , String user, String pass) { this.core = core; - this.profileCache = core.buildCache(); HikariConfig databaseConfig = new HikariConfig(); databaseConfig.setUsername(user); @@ -33,6 +30,8 @@ public class Storage { databasePath = databasePath.replace("{pluginDir}", core.getDataFolder().getAbsolutePath()); + databaseConfig.setThreadFactory(core.getThreadFactory()); + String jdbcUrl = "jdbc:"; if (driver.contains("sqlite")) { jdbcUrl += "sqlite" + "://" + databasePath; @@ -51,15 +50,15 @@ public class Storage { con = dataSource.getConnection(); Statement statement = con.createStatement(); String createDataStmt = "CREATE TABLE IF NOT EXISTS " + PREMIUM_TABLE + " (" - + "`UserID` INTEGER PRIMARY KEY AUTO_INCREMENT, " - + "`UUID` CHAR(36), " - + "`Name` VARCHAR(16) NOT NULL, " - + "`Premium` BOOLEAN NOT NULL, " - + "`LastIp` VARCHAR(255) NOT NULL, " - + "`LastLogin` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, " - + "UNIQUE (`UUID`), " + + "UserID INTEGER PRIMARY KEY AUTO_INCREMENT, " + + "UUID CHAR(36), " + + "Name VARCHAR(16) NOT NULL, " + + "Premium BOOLEAN NOT NULL, " + + "LastIp VARCHAR(255) NOT NULL, " + + "LastLogin TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, " + + "UNIQUE (UUID), " //the premium shouldn't steal the cracked account by changing the name - + "UNIQUE (`Name`) " + + "UNIQUE (Name) " + ")"; if (dataSource.getJdbcUrl().contains("sqlite")) { @@ -72,46 +71,39 @@ public class Storage { } } - public PlayerProfile getProfile(String name, boolean fetch) { - if (profileCache.containsKey(name)) { - return profileCache.get(name); - } else if (fetch) { - Connection con = null; - try { - con = dataSource.getConnection(); - PreparedStatement loadStatement = con.prepareStatement("SELECT * FROM " + PREMIUM_TABLE - + " WHERE `Name`=? LIMIT 1"); - loadStatement.setString(1, name); + public PlayerProfile loadProfile(String name) { + Connection con = null; + try { + con = dataSource.getConnection(); + PreparedStatement loadStatement = con.prepareStatement("SELECT * FROM " + PREMIUM_TABLE + + " WHERE Name=? LIMIT 1"); + loadStatement.setString(1, name); - ResultSet resultSet = loadStatement.executeQuery(); - if (resultSet.next()) { - long userId = resultSet.getInt(1); + ResultSet resultSet = loadStatement.executeQuery(); + if (resultSet.next()) { + long userId = resultSet.getInt(1); - String unparsedUUID = resultSet.getString(2); - UUID uuid; - if (unparsedUUID == null) { - uuid = null; - } else { - uuid = FastLoginCore.parseId(unparsedUUID); - } - -// String name = resultSet.getString(3); - boolean premium = resultSet.getBoolean(4); - String lastIp = resultSet.getString(5); - long lastLogin = resultSet.getTimestamp(6).getTime(); - PlayerProfile playerProfile = new PlayerProfile(userId, uuid, name, premium, lastIp, lastLogin); - profileCache.put(name, playerProfile); - return playerProfile; + String unparsedUUID = resultSet.getString(2); + UUID uuid; + if (unparsedUUID == null) { + uuid = null; } else { - PlayerProfile crackedProfile = new PlayerProfile(null, name, false, ""); - profileCache.put(name, crackedProfile); - return crackedProfile; + uuid = FastLoginCore.parseId(unparsedUUID); } - } catch (SQLException sqlEx) { - core.getLogger().log(Level.SEVERE, "Failed to query profile", sqlEx); - } finally { - closeQuietly(con); + + boolean premium = resultSet.getBoolean(4); + String lastIp = resultSet.getString(5); + long lastLogin = resultSet.getTimestamp(6).getTime(); + PlayerProfile playerProfile = new PlayerProfile(userId, uuid, name, premium, lastIp, lastLogin); + return playerProfile; + } else { + PlayerProfile crackedProfile = new PlayerProfile(null, name, false, ""); + return crackedProfile; } + } catch (SQLException sqlEx) { + core.getLogger().log(Level.SEVERE, "Failed to query profile", sqlEx); + } finally { + closeQuietly(con); } return null; @@ -156,7 +148,6 @@ public class Storage { saveStatement.setString(2, playerProfile.getPlayerName()); saveStatement.setBoolean(3, playerProfile.isPremium()); saveStatement.setString(4, playerProfile.getLastIp()); -// saveStatement.setTimestamp(5, new Timestamp(playerProfile.getLastLogin())); saveStatement.setLong(5, playerProfile.getUserId()); saveStatement.execute(); @@ -174,7 +165,6 @@ public class Storage { public void close() { dataSource.close(); - profileCache.clear(); } private void closeQuietly(Connection con) {