From 10785b32acb0f406603d2b4080eb89beec18183c Mon Sep 17 00:00:00 2001 From: games647 Date: Tue, 7 Jun 2022 18:44:23 +0200 Subject: [PATCH 1/3] Fix anti bot reading the correct values --- .../com/github/games647/fastlogin/bungee/FastLoginBungee.java | 2 +- .../games647/fastlogin/bungee/listener/ConnectListener.java | 2 +- .../github/games647/fastlogin/core/shared/FastLoginCore.java | 4 ++-- .../github/games647/fastlogin/velocity/FastLoginVelocity.java | 2 +- .../games647/fastlogin/velocity/listener/ConnectListener.java | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) 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 b1ed7416..148282c4 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 @@ -100,7 +100,7 @@ public class FastLoginBungee extends Plugin implements PlatformPlugin> { return () -> true; } - int maxCon = botSection.getInt("anti-bot.connections", 200); - long expireTime = botSection.getLong("anti-bot.expire", 5) * 60 * 1_000L; + int maxCon = botSection.getInt("connections", 200); + long expireTime = botSection.getLong("expire", 5) * 60 * 1_000L; if (expireTime > MAX_EXPIRE_RATE) { expireTime = MAX_EXPIRE_RATE; } diff --git a/velocity/src/main/java/com/github/games647/fastlogin/velocity/FastLoginVelocity.java b/velocity/src/main/java/com/github/games647/fastlogin/velocity/FastLoginVelocity.java index d57e6ad7..e15dd3ef 100644 --- a/velocity/src/main/java/com/github/games647/fastlogin/velocity/FastLoginVelocity.java +++ b/velocity/src/main/java/com/github/games647/fastlogin/velocity/FastLoginVelocity.java @@ -96,7 +96,7 @@ public class FastLoginVelocity implements PlatformPlugin { return; } - server.getEventManager().register(this, new ConnectListener(this, core.getRateLimiter())); + server.getEventManager().register(this, new ConnectListener(this, core.getAntiBot())); server.getEventManager().register(this, new PluginMessageListener(this)); server.getChannelRegistrar().register(MinecraftChannelIdentifier.create(getName(), ChangePremiumMessage.CHANGE_CHANNEL)); server.getChannelRegistrar().register(MinecraftChannelIdentifier.create(getName(), SuccessMessage.SUCCESS_CHANNEL)); diff --git a/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java b/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java index 4c03df77..2b51bd2e 100644 --- a/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java +++ b/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java @@ -26,8 +26,8 @@ package com.github.games647.fastlogin.velocity.listener; import com.github.games647.craftapi.UUIDAdapter; -import com.github.games647.fastlogin.core.RateLimiter; import com.github.games647.fastlogin.core.StoredProfile; +import com.github.games647.fastlogin.core.antibot.RateLimiter; import com.github.games647.fastlogin.core.shared.LoginSession; import com.github.games647.fastlogin.velocity.FastLoginVelocity; import com.github.games647.fastlogin.velocity.VelocityLoginSession; From 7cab5993b70e349aed69357cfd970b0eee1ddcf9 Mon Sep 17 00:00:00 2001 From: games647 Date: Tue, 7 Jun 2022 19:18:49 +0200 Subject: [PATCH 2/3] Add license diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java index ab4ceed..9c2fa3a 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 @@ -114,9 +114,9 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin> { private Configuration config; private SQLStorage storage; - private RateLimiter rateLimiter; + private AntiBotService antiBot; private PasswordGenerator

passwordGenerator = new DefaultPasswordGenerator<>(); private AuthPlugin

authPlugin; @@ -122,7 +124,7 @@ public class FastLoginCore

> { // Initialize the resolver based on the config parameter this.resolver = this.config.getBoolean("useProxyAgnosticResolver", false) ? new ProxyAgnosticMojangResolver() : new MojangResolver(); - rateLimiter = createRateLimiter(config.getSection("anti-bot")); + antiBot = createAntiBotService(config.getSection("anti-bot")); Set proxies = config.getStringList("proxies") .stream() .map(HostAndPort::fromString) @@ -144,20 +146,34 @@ public class FastLoginCore

> { resolver.setOutgoingAddresses(addresses); } - private RateLimiter createRateLimiter(Configuration botSection) { - boolean enabled = botSection.getBoolean("enabled", true); - if (!enabled) { + private AntiBotService createAntiBotService(Configuration botSection) { + RateLimiter rateLimiter; + if (botSection.getBoolean("enabled", true)) { + int maxCon = botSection.getInt("connections", 200); + long expireTime = botSection.getLong("expire", 5) * 60 * 1_000L; + if (expireTime > MAX_EXPIRE_RATE) { + expireTime = MAX_EXPIRE_RATE; + } + + rateLimiter = new TickingRateLimiter(Ticker.systemTicker(), maxCon, expireTime); + } else { // no-op rate limiter - return () -> true; + rateLimiter = () -> true; } - int maxCon = botSection.getInt("connections", 200); - long expireTime = botSection.getLong("expire", 5) * 60 * 1_000L; - if (expireTime > MAX_EXPIRE_RATE) { - expireTime = MAX_EXPIRE_RATE; + Action action = Action.Ignore; + switch (botSection.getString("action", "ignore")) { + case "ignore": + action = Action.Ignore; + break; + case "block": + action = Action.Block; + break; + default: + plugin.getLog().warn("Invalid anti bot action - defaulting to ignore"); } - return new TickingRateLimiter(Ticker.systemTicker(), maxCon, expireTime); + return new AntiBotService(plugin.getLog(), rateLimiter, action); } private Configuration loadFile(String fileName) throws IOException { @@ -285,8 +301,8 @@ public class FastLoginCore

> { return authPlugin; } - public RateLimiter getRateLimiter() { - return rateLimiter; + public AntiBotService getAntiBot() { + return antiBot; } public void setAuthPluginHook(AuthPlugin

authPlugin) { diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 1b0905d..3a2ab7a 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -20,6 +20,9 @@ anti-bot: connections: 600 # Amount of minutes after the first connection got inserted will expire and made available expire: 10 + # Action - Which action should be performed when the bucket is full (too many connections) + # Allowed values are: 'ignore' (FastLogin drops handling the player) or 'block' (block this incoming connection) + action: 'ignore' # Request a premium login without forcing the player to type a command # diff --git a/core/src/main/resources/messages.yml b/core/src/main/resources/messages.yml index 8b315ba..33cadaa 100644 --- a/core/src/main/resources/messages.yml +++ b/core/src/main/resources/messages.yml @@ -48,6 +48,9 @@ not-premium-other: '&4Player is not in the premium list' # Admin wanted to change the premium of a user that isn't known to the plugin player-unknown: '&4Player not in the database' +# Player kicked from anti bot feature +kick-antibot: '&4Please wait a moment!' + # ========= Bukkit/Spigot ================ # The user skipped the authentication, because it was a premium player diff --git a/core/src/test/java/com/github/games647/fastlogin/core/TickingRateLimiterTest.java b/core/src/test/java/com/github/games647/fastlogin/core/TickingRateLimiterTest.java index 2c04b6e..3f753cd 100644 --- a/core/src/test/java/com/github/games647/fastlogin/core/TickingRateLimiterTest.java +++ b/core/src/test/java/com/github/games647/fastlogin/core/TickingRateLimiterTest.java @@ -25,6 +25,8 @@ */ package com.github.games647.fastlogin.core; +import com.github.games647.fastlogin.core.antibot.TickingRateLimiter; + import java.time.Duration; import java.util.concurrent.TimeUnit; diff --git a/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java b/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java index 2b51bd2..33c8c31 100644 --- a/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java +++ b/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java @@ -27,7 +27,8 @@ package com.github.games647.fastlogin.velocity.listener; import com.github.games647.craftapi.UUIDAdapter; import com.github.games647.fastlogin.core.StoredProfile; -import com.github.games647.fastlogin.core.antibot.RateLimiter; +import com.github.games647.fastlogin.core.antibot.AntiBotService; +import com.github.games647.fastlogin.core.antibot.AntiBotService.Action; import com.github.games647.fastlogin.core.shared.LoginSession; import com.github.games647.fastlogin.velocity.FastLoginVelocity; import com.github.games647.fastlogin.velocity.VelocityLoginSession; @@ -37,6 +38,7 @@ import com.velocitypowered.api.event.Continuation; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.DisconnectEvent; import com.velocitypowered.api.event.connection.PreLoginEvent; +import com.velocitypowered.api.event.connection.PreLoginEvent.PreLoginComponentResult; import com.velocitypowered.api.event.player.GameProfileRequestEvent; import com.velocitypowered.api.event.player.ServerConnectedEvent; import com.velocitypowered.api.proxy.InboundConnection; @@ -44,19 +46,23 @@ import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.util.GameProfile; +import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; + public class ConnectListener { private final FastLoginVelocity plugin; - private final RateLimiter rateLimiter; + private final AntiBotService antiBotService; - public ConnectListener(FastLoginVelocity plugin, RateLimiter rateLimiter) { + public ConnectListener(FastLoginVelocity plugin, AntiBotService antiBotService) { this.plugin = plugin; - this.rateLimiter = rateLimiter; + this.antiBotService = antiBotService; } @Subscribe @@ -66,16 +72,28 @@ public class ConnectListener { } InboundConnection connection = preLoginEvent.getConnection(); - if (!rateLimiter.tryAcquire()) { - plugin.getLog().warn("Simple Anti-Bot join limit - Ignoring {}", connection); - return; - } - String username = preLoginEvent.getUsername(); - plugin.getLog().info("Incoming login request for {} from {}", username, connection.getRemoteAddress()); - - Runnable asyncPremiumCheck = new AsyncPremiumCheck(plugin, connection, username, continuation, preLoginEvent); - plugin.getScheduler().runAsync(asyncPremiumCheck); + InetSocketAddress address = connection.getRemoteAddress(); + plugin.getLog().info("Incoming login request for {} from {}", username, address); + + Action action = antiBotService.onIncomingConnection(address, username); + switch (action) { + case Ignore: + // just ignore + return; + case Block: + String message = plugin.getCore().getMessage("kick-antibot"); + TextComponent messageParsed = LegacyComponentSerializer.legacyAmpersand().deserialize(message); + + PreLoginComponentResult reason = PreLoginComponentResult.denied(messageParsed); + preLoginEvent.setResult(reason); + break; + case Continue: + default: + Runnable asyncPremiumCheck = new AsyncPremiumCheck(plugin, connection, username, continuation, preLoginEvent); + plugin.getScheduler().runAsync(asyncPremiumCheck); + break; + } } @Subscribe --- .../fastlogin/bukkit/FastLoginBukkit.java | 4 +- .../protocollib/ProtocolLibListener.java | 45 +++++++++++------- .../ProtocolSupportListener.java | 36 +++++++++------ .../bungee/listener/ConnectListener.java | 40 ++++++++++------ .../AntiBotService.java} | 37 +++++++++++++++ .../ProxyAgnosticMojangResolver.java | 0 .../core/{ => antibot}/RateLimiter.java | 2 +- .../{ => antibot}/TickingRateLimiter.java | 2 +- .../core/mojang/UUIDTypeAdapter.java | 25 ---------- .../fastlogin/core/shared/FastLoginCore.java | 46 +++++++++++++------ core/src/main/resources/config.yml | 3 ++ core/src/main/resources/messages.yml | 3 ++ .../core/TickingRateLimiterTest.java | 2 + .../velocity/listener/ConnectListener.java | 42 ++++++++++++----- 14 files changed, 188 insertions(+), 99 deletions(-) rename core/src/main/java/com/github/games647/fastlogin/core/{mojang/MojangApiConnector.java => antibot/AntiBotService.java} (57%) rename core/src/main/java/com/github/games647/fastlogin/core/{mojang => antibot}/ProxyAgnosticMojangResolver.java (100%) rename core/src/main/java/com/github/games647/fastlogin/core/{ => antibot}/RateLimiter.java (96%) rename core/src/main/java/com/github/games647/fastlogin/core/{ => antibot}/TickingRateLimiter.java (98%) delete mode 100644 core/src/main/java/com/github/games647/fastlogin/core/mojang/UUIDTypeAdapter.java 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 ab4ceed1..9c2fa3a7 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 @@ -114,9 +114,9 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin> { private Configuration config; private SQLStorage storage; - private RateLimiter rateLimiter; + private AntiBotService antiBot; private PasswordGenerator

passwordGenerator = new DefaultPasswordGenerator<>(); private AuthPlugin

authPlugin; @@ -122,7 +124,7 @@ public class FastLoginCore

> { // Initialize the resolver based on the config parameter this.resolver = this.config.getBoolean("useProxyAgnosticResolver", false) ? new ProxyAgnosticMojangResolver() : new MojangResolver(); - rateLimiter = createRateLimiter(config.getSection("anti-bot")); + antiBot = createAntiBotService(config.getSection("anti-bot")); Set proxies = config.getStringList("proxies") .stream() .map(HostAndPort::fromString) @@ -144,20 +146,34 @@ public class FastLoginCore

> { resolver.setOutgoingAddresses(addresses); } - private RateLimiter createRateLimiter(Configuration botSection) { - boolean enabled = botSection.getBoolean("enabled", true); - if (!enabled) { + private AntiBotService createAntiBotService(Configuration botSection) { + RateLimiter rateLimiter; + if (botSection.getBoolean("enabled", true)) { + int maxCon = botSection.getInt("connections", 200); + long expireTime = botSection.getLong("expire", 5) * 60 * 1_000L; + if (expireTime > MAX_EXPIRE_RATE) { + expireTime = MAX_EXPIRE_RATE; + } + + rateLimiter = new TickingRateLimiter(Ticker.systemTicker(), maxCon, expireTime); + } else { // no-op rate limiter - return () -> true; + rateLimiter = () -> true; } - int maxCon = botSection.getInt("connections", 200); - long expireTime = botSection.getLong("expire", 5) * 60 * 1_000L; - if (expireTime > MAX_EXPIRE_RATE) { - expireTime = MAX_EXPIRE_RATE; + Action action = Action.Ignore; + switch (botSection.getString("action", "ignore")) { + case "ignore": + action = Action.Ignore; + break; + case "block": + action = Action.Block; + break; + default: + plugin.getLog().warn("Invalid anti bot action - defaulting to ignore"); } - return new TickingRateLimiter(Ticker.systemTicker(), maxCon, expireTime); + return new AntiBotService(plugin.getLog(), rateLimiter, action); } private Configuration loadFile(String fileName) throws IOException { @@ -285,8 +301,8 @@ public class FastLoginCore

> { return authPlugin; } - public RateLimiter getRateLimiter() { - return rateLimiter; + public AntiBotService getAntiBot() { + return antiBot; } public void setAuthPluginHook(AuthPlugin

authPlugin) { diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 1b0905d6..3a2ab7a9 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -20,6 +20,9 @@ anti-bot: connections: 600 # Amount of minutes after the first connection got inserted will expire and made available expire: 10 + # Action - Which action should be performed when the bucket is full (too many connections) + # Allowed values are: 'ignore' (FastLogin drops handling the player) or 'block' (block this incoming connection) + action: 'ignore' # Request a premium login without forcing the player to type a command # diff --git a/core/src/main/resources/messages.yml b/core/src/main/resources/messages.yml index 8b315baa..33cadaad 100644 --- a/core/src/main/resources/messages.yml +++ b/core/src/main/resources/messages.yml @@ -48,6 +48,9 @@ not-premium-other: '&4Player is not in the premium list' # Admin wanted to change the premium of a user that isn't known to the plugin player-unknown: '&4Player not in the database' +# Player kicked from anti bot feature +kick-antibot: '&4Please wait a moment!' + # ========= Bukkit/Spigot ================ # The user skipped the authentication, because it was a premium player diff --git a/core/src/test/java/com/github/games647/fastlogin/core/TickingRateLimiterTest.java b/core/src/test/java/com/github/games647/fastlogin/core/TickingRateLimiterTest.java index 2c04b6e3..3f753cd4 100644 --- a/core/src/test/java/com/github/games647/fastlogin/core/TickingRateLimiterTest.java +++ b/core/src/test/java/com/github/games647/fastlogin/core/TickingRateLimiterTest.java @@ -25,6 +25,8 @@ */ package com.github.games647.fastlogin.core; +import com.github.games647.fastlogin.core.antibot.TickingRateLimiter; + import java.time.Duration; import java.util.concurrent.TimeUnit; diff --git a/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java b/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java index 2b51bd2e..33c8c311 100644 --- a/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java +++ b/velocity/src/main/java/com/github/games647/fastlogin/velocity/listener/ConnectListener.java @@ -27,7 +27,8 @@ package com.github.games647.fastlogin.velocity.listener; import com.github.games647.craftapi.UUIDAdapter; import com.github.games647.fastlogin.core.StoredProfile; -import com.github.games647.fastlogin.core.antibot.RateLimiter; +import com.github.games647.fastlogin.core.antibot.AntiBotService; +import com.github.games647.fastlogin.core.antibot.AntiBotService.Action; import com.github.games647.fastlogin.core.shared.LoginSession; import com.github.games647.fastlogin.velocity.FastLoginVelocity; import com.github.games647.fastlogin.velocity.VelocityLoginSession; @@ -37,6 +38,7 @@ import com.velocitypowered.api.event.Continuation; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.DisconnectEvent; import com.velocitypowered.api.event.connection.PreLoginEvent; +import com.velocitypowered.api.event.connection.PreLoginEvent.PreLoginComponentResult; import com.velocitypowered.api.event.player.GameProfileRequestEvent; import com.velocitypowered.api.event.player.ServerConnectedEvent; import com.velocitypowered.api.proxy.InboundConnection; @@ -44,19 +46,23 @@ import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.util.GameProfile; +import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; + public class ConnectListener { private final FastLoginVelocity plugin; - private final RateLimiter rateLimiter; + private final AntiBotService antiBotService; - public ConnectListener(FastLoginVelocity plugin, RateLimiter rateLimiter) { + public ConnectListener(FastLoginVelocity plugin, AntiBotService antiBotService) { this.plugin = plugin; - this.rateLimiter = rateLimiter; + this.antiBotService = antiBotService; } @Subscribe @@ -66,16 +72,28 @@ public class ConnectListener { } InboundConnection connection = preLoginEvent.getConnection(); - if (!rateLimiter.tryAcquire()) { - plugin.getLog().warn("Simple Anti-Bot join limit - Ignoring {}", connection); - return; - } - String username = preLoginEvent.getUsername(); - plugin.getLog().info("Incoming login request for {} from {}", username, connection.getRemoteAddress()); + InetSocketAddress address = connection.getRemoteAddress(); + plugin.getLog().info("Incoming login request for {} from {}", username, address); - Runnable asyncPremiumCheck = new AsyncPremiumCheck(plugin, connection, username, continuation, preLoginEvent); - plugin.getScheduler().runAsync(asyncPremiumCheck); + Action action = antiBotService.onIncomingConnection(address, username); + switch (action) { + case Ignore: + // just ignore + return; + case Block: + String message = plugin.getCore().getMessage("kick-antibot"); + TextComponent messageParsed = LegacyComponentSerializer.legacyAmpersand().deserialize(message); + + PreLoginComponentResult reason = PreLoginComponentResult.denied(messageParsed); + preLoginEvent.setResult(reason); + break; + case Continue: + default: + Runnable asyncPremiumCheck = new AsyncPremiumCheck(plugin, connection, username, continuation, preLoginEvent); + plugin.getScheduler().runAsync(asyncPremiumCheck); + break; + } } @Subscribe From 32fe2cdf4e57b5acc1b598108be18376759dff95 Mon Sep 17 00:00:00 2001 From: games647 Date: Tue, 7 Jun 2022 19:29:06 +0200 Subject: [PATCH 3/3] Check for valid session before starting a new thread This could reduce load for malicious senders as there have to be session active to start the expensive operation of creating a new thread. --- .../protocollib/ProtocolLibListener.java | 13 ++++- .../protocollib/VerifyResponseTask.java | 56 +++++++++---------- 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java index 3c161b7e..d1f83a61 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java @@ -30,6 +30,7 @@ import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; +import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.core.antibot.AntiBotService; import com.github.games647.fastlogin.core.antibot.AntiBotService.Action; @@ -124,9 +125,15 @@ public class ProtocolLibListener extends PacketAdapter { private void onEncryptionBegin(PacketEvent packetEvent, Player sender) { byte[] sharedSecret = packetEvent.getPacket().getByteArrays().read(0); - packetEvent.getAsyncMarker().incrementProcessingDelay(); - Runnable verifyTask = new VerifyResponseTask(plugin, packetEvent, sender, sharedSecret, keyPair); - plugin.getScheduler().runAsync(verifyTask); + BukkitLoginSession session = plugin.getSession(sender.getAddress()); + if (session == null) { + plugin.getLog().warn("GameProfile {} tried to send encryption response at invalid state", sender.getAddress()); + sender.kickPlayer(plugin.getCore().getMessage("invalid-request")); + } else { + packetEvent.getAsyncMarker().incrementProcessingDelay(); + Runnable verifyTask = new VerifyResponseTask(plugin, packetEvent, sender, session, sharedSecret, keyPair); + plugin.getScheduler().runAsync(verifyTask); + } } private void onLogin(PacketEvent packetEvent, Player player, String username) { 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 84409262..54d525c2 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 @@ -79,16 +79,20 @@ public class VerifyResponseTask implements Runnable { private final Player player; + private final BukkitLoginSession session; + private final byte[] sharedSecret; private static Method encryptMethod; private static Method cipherMethod; - public VerifyResponseTask(FastLoginBukkit plugin, PacketEvent packetEvent, Player player, + public VerifyResponseTask(FastLoginBukkit plugin, PacketEvent packetEvent, + Player player, BukkitLoginSession session, byte[] sharedSecret, KeyPair keyPair) { this.plugin = plugin; this.packetEvent = packetEvent; this.player = player; + this.session = session; this.sharedSecret = Arrays.copyOf(sharedSecret, sharedSecret.length); this.serverKey = keyPair; } @@ -96,14 +100,7 @@ public class VerifyResponseTask implements Runnable { @Override public void run() { try { - BukkitLoginSession session = plugin.getSession(player.getAddress()); - if (session == null) { - disconnect("invalid-request", - "GameProfile {0} tried to send encryption response at invalid state", - player.getAddress()); - } else { - verifyResponse(session); - } + verifyResponse(session); } finally { //this is a fake packet; it shouldn't be sent to the server synchronized (packetEvent.getAsyncMarker().getProcessingLock()) { @@ -143,25 +140,7 @@ public class VerifyResponseTask implements Runnable { InetAddress address = socketAddress.getAddress(); Optional response = resolver.hasJoined(requestedUsername, serverId, address); if (response.isPresent()) { - Verification verification = response.get(); - plugin.getLog().info("Profile {} has a verified premium account", requestedUsername); - String realUsername = verification.getName(); - if (realUsername == null) { - disconnect("invalid-session", "Username field null for {}", requestedUsername); - return; - } - - SkinProperty[] properties = verification.getProperties(); - if (properties.length > 0) { - session.setSkinProperty(properties[0]); - } - - session.setVerifiedUsername(realUsername); - session.setUuid(verification.getId()); - session.setVerified(true); - - setPremiumUUID(session.getUuid()); - receiveFakeStartPacket(realUsername); + encryptConnection(session, requestedUsername, response.get()); } else { //user tried to fake an authentication disconnect("invalid-session", "GameProfile {} ({}) tried to log in with an invalid session. ServerId: {}", session.getRequestUsername(), socketAddress, serverId); @@ -171,6 +150,27 @@ public class VerifyResponseTask implements Runnable { } } + private void encryptConnection(BukkitLoginSession session, String requestedUsername, Verification verification) { + plugin.getLog().info("Profile {} has a verified premium account", requestedUsername); + String realUsername = verification.getName(); + if (realUsername == null) { + disconnect("invalid-session", "Username field null for {}", requestedUsername); + return; + } + + SkinProperty[] properties = verification.getProperties(); + if (properties.length > 0) { + session.setSkinProperty(properties[0]); + } + + session.setVerifiedUsername(realUsername); + session.setUuid(verification.getId()); + session.setVerified(true); + + setPremiumUUID(session.getUuid()); + receiveFakeStartPacket(realUsername); + } + private void setPremiumUUID(UUID premiumUUID) { if (plugin.getConfig().getBoolean("premiumUuid") && premiumUUID != null) { try {