diff --git a/CHANGELOG.md b/CHANGELOG.md index 010fb1ba..060fd770 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +######1.9 + +* Added second attempt login -> cracked login + ######1.8 * Added autoIn importer diff --git a/bukkit/pom.xml b/bukkit/pom.xml index d0449c82..57b872a5 100644 --- a/bukkit/pom.xml +++ b/bukkit/pom.xml @@ -5,7 +5,7 @@ com.github.games647 fastlogin - 1.8 + 1.9 ../pom.xml 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 f1e26a63..3eb6f1d8 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 @@ -2,11 +2,14 @@ package com.github.games647.fastlogin.bukkit; import com.github.games647.fastlogin.core.FastLoginCore; import com.google.common.base.Charsets; +import com.google.common.cache.CacheLoader; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.io.File; import java.io.InputStreamReader; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; import org.bukkit.ChatColor; @@ -14,9 +17,30 @@ import org.bukkit.configuration.file.YamlConfiguration; public class BukkitCore extends FastLoginCore { + public static ConcurrentMap buildCache(int minutes, int maxSize) { + CompatibleCacheBuilder builder = CompatibleCacheBuilder.newBuilder(); + + if (minutes > 0) { + builder.expireAfterWrite(minutes, TimeUnit.MINUTES); + } + + if (maxSize > 0) { + builder.maximumSize(maxSize); + } + + return builder.build(new CacheLoader() { + @Override + public V load(K key) throws Exception { + throw new UnsupportedOperationException("Not supported yet."); + } + }); + } + private final FastLoginBukkit plugin; public BukkitCore(FastLoginBukkit plugin) { + super(BukkitCore.buildCache(5, 0)); + this.plugin = plugin; } 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 9459b6dd..387c987c 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 @@ -15,7 +15,6 @@ import com.github.games647.fastlogin.bukkit.listener.protocollib.StartPacketList import com.github.games647.fastlogin.bukkit.listener.protocolsupport.ProtocolSupportListener; import com.github.games647.fastlogin.bukkit.tasks.DelayedAuthHook; import com.github.games647.fastlogin.core.FastLoginCore; -import com.google.common.cache.CacheLoader; import com.google.common.collect.Sets; import java.security.KeyPair; @@ -23,7 +22,6 @@ import java.util.List; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; import org.bukkit.entity.Player; @@ -47,7 +45,7 @@ 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 = buildCache(1, -1); + private final ConcurrentMap session = BukkitCore.buildCache(1, -1); //1 minutes should be enough as a timeout for bad internet connection (Server, Client and Mojang) private BukkitAuthPlugin authPlugin; @@ -60,7 +58,8 @@ public class FastLoginBukkit extends JavaPlugin { List ipAddresses = getConfig().getStringList("ip-addresses"); int requestLimit = getConfig().getInt("mojang-request-limit"); - MojangApiBukkit mojangApi = new MojangApiBukkit(buildCache(10, -1), getLogger(), ipAddresses, requestLimit); + ConcurrentMap requestCache = BukkitCore.buildCache(10, -1); + MojangApiBukkit mojangApi = new MojangApiBukkit(requestCache, getLogger(), ipAddresses, requestLimit); core.setMojangApiConnector(mojangApi); try { @@ -220,23 +219,4 @@ public class FastLoginBukkit extends JavaPlugin { this.serverStarted = true; } } - - private ConcurrentMap buildCache(int minutes, int maxSize) { - CompatibleCacheBuilder builder = CompatibleCacheBuilder.newBuilder(); - - if (minutes > 0) { - builder.expireAfterWrite(minutes, TimeUnit.MINUTES); - } - - if (maxSize > 0) { - builder.maximumSize(maxSize); - } - - return builder.build(new CacheLoader() { - @Override - public V load(K key) throws Exception { - throw new UnsupportedOperationException("Not supported yet."); - } - }); - } } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java index acdf3e77..dad9d4f4 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/NameCheckTask.java @@ -54,7 +54,18 @@ public class NameCheckTask implements Runnable { if (profile.getUserId() == -1) { UUID premiumUUID = null; - + + String ip = player.getAddress().getAddress().getHostAddress(); + if (plugin.getCore().getPendingLogins().containsKey(ip + username) + && plugin.getConfig().getBoolean("secondAttemptCracked")) { + plugin.getLogger().log(Level.INFO, "Second attempt login -> cracked {0}", username); + + //first login request failed so make a cracked session + BukkitLoginSession loginSession = new BukkitLoginSession(username, profile); + plugin.getSessions().put(player.getAddress().toString(), loginSession); + return; + } + //user not exists in the db try { boolean isRegistered = plugin.getAuthPlugin().isRegistered(username); @@ -105,6 +116,9 @@ public class NameCheckTask implements Runnable { boolean success = sentEncryptionRequest(player, serverId, verify); if (success) { + String ip = player.getAddress().getAddress().getHostAddress(); + plugin.getCore().getPendingLogins().put(ip + username, new Object()); + BukkitLoginSession playerSession = new BukkitLoginSession(username, serverId, verify, registered, profile); plugin.getSessions().put(player.getAddress().toString(), playerSession); //cancel only if the player has a paid account otherwise login as normal offline player diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java index 33330566..c9e9538d 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java @@ -50,6 +50,9 @@ public class VerifyResponseTask implements Runnable { disconnect(plugin.getCore().getMessage("invalid-requst"), true , "Player {0} tried to send encryption response at invalid state", fromPlayer.getAddress()); } else { + String ip = fromPlayer.getAddress().getAddress().getHostAddress(); + plugin.getCore().getPendingLogins().remove(ip + session.getUsername()); + verifyResponse(session); } } finally { diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolSupportListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolSupportListener.java index 4bce5c75..66a8c458 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolSupportListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolSupportListener.java @@ -31,9 +31,10 @@ public class ProtocolSupportListener implements Listener { } String username = loginStartEvent.getName(); + InetSocketAddress address = loginStartEvent.getAddress(); //remove old data every time on a new login in order to keep the session only for one person - plugin.getSessions().remove(loginStartEvent.getAddress().toString()); + plugin.getSessions().remove(address.toString()); BukkitAuthPlugin authPlugin = plugin.getAuthPlugin(); if (authPlugin == null) { @@ -43,6 +44,18 @@ public class ProtocolSupportListener implements Listener { PlayerProfile profile = plugin.getCore().getStorage().loadProfile(username); if (profile != null) { if (profile.getUserId() == -1) { + + String ip = address.getAddress().getHostAddress(); + if (plugin.getCore().getPendingLogins().containsKey(ip + username) + && plugin.getConfig().getBoolean("secondAttemptCracked")) { + plugin.getLogger().log(Level.INFO, "Second attempt login -> cracked {0}", username); + + //first login request failed so make a cracked session + BukkitLoginSession loginSession = new BukkitLoginSession(username, profile); + plugin.getSessions().put(address.toString(), loginSession); + return; + } + UUID premiumUUID = null; //user not exists in the db @@ -70,7 +83,7 @@ public class ProtocolSupportListener implements Listener { //no premium check passed so we save it as a cracked player BukkitLoginSession loginSession = new BukkitLoginSession(username, profile); - plugin.getSessions().put(loginStartEvent.getAddress().toString(), loginSession); + plugin.getSessions().put(address.toString(), loginSession); } catch (Exception ex) { plugin.getLogger().log(Level.SEVERE, "Failed to query isRegistered", ex); } @@ -78,7 +91,7 @@ public class ProtocolSupportListener implements Listener { startPremiumSession(username, loginStartEvent, true, profile); } else { BukkitLoginSession loginSession = new BukkitLoginSession(username, profile); - plugin.getSessions().put(loginStartEvent.getAddress().toString(), loginSession); + plugin.getSessions().put(address.toString(), loginSession); } } } @@ -90,17 +103,23 @@ public class ProtocolSupportListener implements Listener { InetSocketAddress address = propertiesResolveEvent.getAddress(); BukkitLoginSession session = plugin.getSessions().get(address.toString()); if (session != null) { + String ip = address.getAddress().getHostAddress(); + plugin.getCore().getPendingLogins().remove(ip + session.getUsername()); + session.setVerified(true); } } } - private void startPremiumSession(String playerName, PlayerLoginStartEvent loginStartEvent, boolean registered + private void startPremiumSession(String username, PlayerLoginStartEvent loginStartEvent, boolean registered , PlayerProfile playerProfile) { loginStartEvent.setOnlineMode(true); InetSocketAddress address = loginStartEvent.getAddress(); - BukkitLoginSession playerSession = new BukkitLoginSession(playerName, null, null, registered, playerProfile); + String ip = address.getAddress().getHostAddress(); + plugin.getCore().getPendingLogins().put(ip + username, new Object()); + + BukkitLoginSession playerSession = new BukkitLoginSession(username, null, null, registered, playerProfile); plugin.getSessions().put(address.toString(), playerSession); if (plugin.getConfig().getBoolean("premiumUuid")) { loginStartEvent.setUseOnlineModeUUID(true); diff --git a/bungee/pom.xml b/bungee/pom.xml index e8191fbd..2d1df209 100644 --- a/bungee/pom.xml +++ b/bungee/pom.xml @@ -5,7 +5,7 @@ com.github.games647 fastlogin - 1.8 + 1.9 ../pom.xml 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 22cb69ad..c5982334 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,6 +1,7 @@ package com.github.games647.fastlogin.bungee; import com.github.games647.fastlogin.core.FastLoginCore; +import com.google.common.cache.CacheBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.io.File; @@ -8,10 +9,11 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; -import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.scheduler.GroupedThreadFactory; import net.md_5.bungee.config.Configuration; import net.md_5.bungee.config.ConfigurationProvider; @@ -22,6 +24,8 @@ public class BungeeCore extends FastLoginCore { private final FastLoginBungee plugin; public BungeeCore(FastLoginBungee plugin) { + super(CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build().asMap()); + this.plugin = plugin; } 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 387f3104..0ac4a027 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 @@ -59,6 +59,9 @@ public class PlayerConnectionListener implements Listener { PendingConnection connection = loginEvent.getConnection(); String username = connection.getName(); if (connection.isOnlineMode()) { + String ip = connection.getAddress().getAddress().getHostAddress(); + plugin.getCore().getPendingLogins().remove(ip + username); + LoginSession session = plugin.getSession().get(connection); PlayerProfile playerProfile = session.getProfile(); playerProfile.setUuid(connection.getUniqueId()); diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/tasks/AsyncPremiumCheck.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/tasks/AsyncPremiumCheck.java index 58089930..7b7475a4 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/tasks/AsyncPremiumCheck.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/tasks/AsyncPremiumCheck.java @@ -27,13 +27,23 @@ public class AsyncPremiumCheck implements Runnable { plugin.getSession().remove(connection); String username = connection.getName(); - try { - PlayerProfile profile = plugin.getCore().getStorage().loadProfile(username); - if (profile == null) { - return; - } + PlayerProfile profile = plugin.getCore().getStorage().loadProfile(username); + if (profile == null) { + return; + } + try { if (profile.getUserId() == -1) { + String ip = connection.getAddress().getAddress().getHostAddress(); + if (plugin.getCore().getPendingLogins().containsKey(ip + username) + && plugin.getConfig().getBoolean("secondAttemptCracked")) { + plugin.getLogger().log(Level.INFO, "Second attempt login -> cracked {0}", username); + + //first login request failed so make a cracked session + plugin.getSession().put(connection, new BungeeLoginSession(username, false, profile)); + return; + } + UUID premiumUUID = null; if (plugin.getConfig().getBoolean("nameChangeCheck") || plugin.getConfig().getBoolean("autoRegister")) { premiumUUID = plugin.getCore().getMojangApiConnector().getPremiumUUID(username); @@ -89,5 +99,8 @@ public class AsyncPremiumCheck implements Runnable { private void requestPremiumLogin(PendingConnection con, PlayerProfile profile, String username, boolean register) { con.setOnlineMode(true); plugin.getSession().put(con, new BungeeLoginSession(username, register, profile)); + + String ip = con.getAddress().getAddress().getHostAddress(); + plugin.getCore().getPendingLogins().put(ip + username, new Object()); } } diff --git a/core/pom.xml b/core/pom.xml index f1260ee6..914ab156 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -5,7 +5,7 @@ com.github.games647 fastlogin - 1.8 + 1.9 ../pom.xml 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 d0a75969..5175bb11 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 @@ -11,6 +11,7 @@ import java.sql.SQLException; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ThreadFactory; import java.util.logging.Level; import java.util.logging.Logger; @@ -30,9 +31,16 @@ public abstract class FastLoginCore { } protected final Map localeMessages = new ConcurrentHashMap<>(); + + private final ConcurrentMap pendingLogins; + private MojangApiConnector mojangApiConnector; private AuthStorage storage; + public FastLoginCore(ConcurrentMap pendingLogins) { + this.pendingLogins = pendingLogins; + } + public void setMojangApiConnector(MojangApiConnector mojangApiConnector) { this.mojangApiConnector = mojangApiConnector; } @@ -110,6 +118,10 @@ public abstract class FastLoginCore { return false; } + public ConcurrentMap getPendingLogins() { + return pendingLogins; + } + public void close() { if (storage != null) { storage.close(); diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 8935e395..7d91509e 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -21,6 +21,14 @@ # For more information: https://github.com/games647/FastLogin#why-do-players-have-to-invoke-a-command autoRegister: false +# This is extra configuration option to the feature above. If we request a premium authentication from a player who +# isn't actual premium but used a premium username, the player will disconnect with the reason "invalid session" or +# "bad login". +# +# If you activate this, we are remembering this player and do not force another premium authentication if the player +# tries to join again, so the player could join as cracked player. +secondAttemptCracked: false + # If this plugin detected that a player has a premium, it can also set the associated # uuid from that account. So if the players changes their usernames, they will still have # the same playerdata (inventory, permissions, ...) diff --git a/pom.xml b/pom.xml index 7c6049c3..d4568e9b 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ pom FastLogin - 1.8 + 1.9 2015 https://www.spigotmc.org/resources/fastlogin.14153/ diff --git a/universal/pom.xml b/universal/pom.xml index 5949337a..753184a8 100644 --- a/universal/pom.xml +++ b/universal/pom.xml @@ -5,7 +5,7 @@ com.github.games647 fastlogin - 1.8 + 1.9 ../pom.xml