mirror of
https://github.com/TuxCoding/FastLogin.git
synced 2026-01-26 09:02:19 +01:00
bb1cbb79f22c450a8aad71a67ad34dbcd085b2d6
823 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bb1cbb79f2 | Support newer Paper configuration with clearer error messages | ||
|
|
cf356099a0 | Fix public key timestamp verification. | ||
|
|
91c01e3422 |
Reuse verify token tick message for signature verification
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 6c578ff..92e1dcd 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
@@ -153,11 +153,11 @@ public class ProtocolLibListener extends PacketAdapter {
Runnable verifyTask = new VerifyResponseTask(plugin, packetEvent, sender, sharedSecret, keyPair);
plugin.getScheduler().runAsync(verifyTask);
} else {
- sender.kickPlayer("Invalid signature");
+ sender.kickPlayer(plugin.getCore().getMessage("invalid-verify-token"));
plugin.getLog().error("Invalid signature from player {}", sender);
}
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException signatureEx) {
- sender.kickPlayer("Invalid signature");
+ sender.kickPlayer(plugin.getCore().getMessage("invalid-verify-token"));
plugin.getLog().error("Invalid signature from player {}", sender, signatureEx);
}
}
|
||
|
|
c118430bf5 | Kick players using an invalid public key | ||
|
|
ce59172839 |
Log signature verification errors to help administrators
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 c3e159a..da28f38 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
@@ -154,9 +154,11 @@ public class ProtocolLibListener extends PacketAdapter {
plugin.getScheduler().runAsync(verifyTask);
} else {
sender.kickPlayer("Invalid signature");
+ plugin.getLog().error("Invalid signature from player {}", sender);
}
- } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException signatureEx) {
sender.kickPlayer("Invalid signature");
+ plugin.getLog().error("Invalid signature from player {}", sender, signatureEx);
}
}
}
|
||
|
|
34e63b7eae | Make profile key optional | ||
|
|
e8bb3ec7a9 | Validate other encryption methods | ||
|
|
1d46640b42 | Limit length of server keys | ||
|
|
a0fddd69aa | Decrease necessary entropy for running tests | ||
|
|
700b889aa9 | Improve precision and flexibility of encrypt methods | ||
|
|
3767b022a9 | Migrate to guava hashing to replace unneeded exceptions | ||
|
|
11077a002d | Migrate public key to record | ||
|
|
d9bf7267a6 | Test valid server key pairs | ||
|
|
53e6fe6ddf | Missing synchronization access to the username | ||
|
|
1c528fb9cb |
Clean up
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BungeeManager.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BungeeManager.java
index 49ff879..7149238 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BungeeManager.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BungeeManager.java
@@ -36,6 +36,7 @@ import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@@ -62,7 +63,7 @@ public class BungeeManager {
private final FastLoginBukkit plugin;
private boolean enabled;
- private final Set<UUID> firedJoinEvents = new HashSet<>();
+ private final Collection<UUID> firedJoinEvents = new HashSet<>();
public BungeeManager(FastLoginBukkit plugin) {
this.plugin = plugin;
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/CrackedCommand.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/CrackedCommand.java
index a6ac9b7..6153338 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/CrackedCommand.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/CrackedCommand.java
@@ -44,7 +44,7 @@ public class CrackedCommand extends ToggleCommand {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (args.length == 0) {
- onCrackedSelf(sender, command, args);
+ onCrackedSelf(sender);
} else {
onCrackedOther(sender, command, args);
}
@@ -52,7 +52,7 @@ public class CrackedCommand extends ToggleCommand {
return true;
}
- private void onCrackedSelf(CommandSender sender, Command cmd, String[] args) {
+ private void onCrackedSelf(CommandSender sender) {
if (isConsole(sender)) {
return;
}
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/PremiumCommand.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/PremiumCommand.java
index 26b6d31..9f1ef98 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/PremiumCommand.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/PremiumCommand.java
@@ -51,7 +51,7 @@ public class PremiumCommand extends ToggleCommand {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (args.length == 0) {
- onPremiumSelf(sender, command, args);
+ onPremiumSelf(sender);
} else {
onPremiumOther(sender, command, args);
}
@@ -59,7 +59,7 @@ public class PremiumCommand extends ToggleCommand {
return true;
}
- private void onPremiumSelf(CommandSender sender, Command cmd, String[] args) {
+ private void onPremiumSelf(CommandSender sender) {
if (isConsole(sender)) {
return;
}
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/event/BukkitFastLoginAutoLoginEvent.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/event/BukkitFastLoginAutoLoginEvent.java
index 8c61330..6412c6d 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/event/BukkitFastLoginAutoLoginEvent.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/event/BukkitFastLoginAutoLoginEvent.java
@@ -28,6 +28,7 @@ package com.github.games647.fastlogin.bukkit.event;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSession;
import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent;
+
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/event/BukkitFastLoginPreLoginEvent.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/event/BukkitFastLoginPreLoginEvent.java
index 6b2edfc..5bf6df9 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/event/BukkitFastLoginPreLoginEvent.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/event/BukkitFastLoginPreLoginEvent.java
@@ -28,6 +28,7 @@ package com.github.games647.fastlogin.bukkit.event;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSource;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
+
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/event/BukkitFastLoginPremiumToggleEvent.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/event/BukkitFastLoginPremiumToggleEvent.java
index 146efb0..0904826 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/event/BukkitFastLoginPremiumToggleEvent.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/event/BukkitFastLoginPremiumToggleEvent.java
@@ -27,6 +27,7 @@ package com.github.games647.fastlogin.bukkit.event;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent;
+
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java
index fecfb73..45d5a5f 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java
@@ -28,18 +28,20 @@ package com.github.games647.fastlogin.bukkit.hook;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
+
import fr.xephi.authme.api.v3.AuthMeApi;
import fr.xephi.authme.events.RestoreSessionEvent;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.process.register.executors.ApiPasswordRegisterParams;
import fr.xephi.authme.process.register.executors.RegistrationMethod;
+
+import java.lang.reflect.Field;
+
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
-import java.lang.reflect.Field;
-
/**
* GitHub: <a href="https://github.com/Xephi/AuthMeReloaded/">...</a>
* <p>
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/PaperCacheListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/PaperCacheListener.java
index e444ed9..44ff6ea 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/PaperCacheListener.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/PaperCacheListener.java
@@ -29,6 +29,7 @@ import com.destroystokyo.paper.profile.ProfileProperty;
import com.github.games647.craftapi.model.skin.Textures;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
+
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ManualNameChange.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ManualNameChange.java
index cdf3999..2a36e88 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ManualNameChange.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ManualNameChange.java
@@ -25,6 +25,7 @@
*/
package com.github.games647.fastlogin.bukkit.listener.protocollib;
+import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
@@ -36,8 +37,6 @@ import org.geysermc.floodgate.api.FloodgateApi;
import static com.comphenix.protocol.PacketType.Login.Client.START;
-import com.comphenix.protocol.ProtocolLibrary;
-
/**
* Manually inject Floodgate player name prefixes.
* <br>
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 485c065..d3b38ea 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
@@ -49,7 +49,7 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
private final FastLoginBukkit plugin;
private final PacketEvent packetEvent;
- private final PublicKey publicKey;
+ private final PublicKey serverKey;
private final Random random;
@@ -57,12 +57,12 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
private final String username;
public NameCheckTask(FastLoginBukkit plugin, Random random, Player player, PacketEvent packetEvent,
- String username, PublicKey publicKey) {
+ String username, PublicKey serverKey) {
super(plugin.getCore(), plugin.getCore().getAuthPluginHook(), plugin.getBedrockService());
this.plugin = plugin;
this.packetEvent = packetEvent;
- this.publicKey = publicKey;
+ this.serverKey = serverKey;
this.random = random;
this.player = player;
this.username = username;
@@ -71,9 +71,9 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
@Override
public void run() {
try {
- Optional<WrappedProfileKeyData> publicKey = packetEvent.getPacket().getOptionals(BukkitConverters.getWrappedPublicKeyDataConverter()).read(0);
+ Optional<WrappedProfileKeyData> clientKey = packetEvent.getPacket().getOptionals(BukkitConverters.getWrappedPublicKeyDataConverter()).read(0);
- super.onLogin(username, new ProtocolLibLoginSource(player, random, publicKey.get(), this.publicKey));
+ super.onLogin(username, new ProtocolLibLoginSource(player, random, clientKey.get(), serverKey));
} finally {
ProtocolLibrary.getProtocolManager().getAsynchronousManager().signalPacketTransmission(packetEvent);
}
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 55a8f33..89d855d 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
@@ -127,7 +127,7 @@ public class ProtocolLibListener extends PacketAdapter {
}
}
- private Boolean isFastLoginPacket(PacketEvent packetEvent) {
+ private boolean isFastLoginPacket(PacketEvent packetEvent) {
return packetEvent.getPacket().getMeta(SOURCE_META_KEY)
.map(val -> val.equals(plugin.getName()))
.orElse(false);
@@ -146,7 +146,7 @@ public class ProtocolLibListener extends PacketAdapter {
long salt = FuzzyReflection.getFieldValue(signatureData, Long.TYPE, true);
byte[] signature = FuzzyReflection.getFieldValue(signatureData, byte[].class, true);
- PublicKey publicKey = session.getClientPublicKey().getKey();
+ PublicKey publicKey = session.getClientPublicKey().key();
try {
if (EncryptionUtil.verifySignedNonce(session.getVerifyToken(), publicKey, salt, signature)) {
packetEvent.getAsyncMarker().incrementProcessingDelay();
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java
index d87b602..d4c1130 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java
@@ -33,7 +33,6 @@ import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
import com.github.games647.fastlogin.core.shared.LoginSource;
-import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.security.PublicKey;
import java.util.Arrays;
@@ -64,7 +63,7 @@ class ProtocolLibLoginSource implements LoginSource {
}
@Override
- public void enableOnlinemode() throws InvocationTargetException {
+ public void enableOnlinemode() {
verifyToken = EncryptionUtil.generateVerifyToken(random);
/*
@@ -92,7 +91,7 @@ class ProtocolLibLoginSource implements LoginSource {
}
@Override
- public void kick(String message) throws InvocationTargetException {
+ public void kick(String message) {
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
PacketContainer kickPacket = new PacketContainer(DISCONNECT);
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SkinApplyListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SkinApplyListener.java
index 7d43835..3d4a807 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SkinApplyListener.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SkinApplyListener.java
@@ -34,6 +34,9 @@ import com.comphenix.protocol.wrappers.WrappedSignedProperty;
import com.github.games647.craftapi.model.skin.Textures;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
+
+import java.lang.reflect.InvocationTargetException;
+
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -41,8 +44,6 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerLoginEvent.Result;
-import java.lang.reflect.InvocationTargetException;
-
public class SkinApplyListener implements Listener {
private static final Class<?> GAME_PROFILE = MinecraftReflection.getGameProfileClass();
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/task/FloodgateAuthTask.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/task/FloodgateAuthTask.java
index acb3597..ef9fed0 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/task/FloodgateAuthTask.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/task/FloodgateAuthTask.java
@@ -25,6 +25,11 @@
*/
package com.github.games647.fastlogin.bukkit.task;
+import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
+import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
+import com.github.games647.fastlogin.core.shared.FastLoginCore;
+import com.github.games647.fastlogin.core.shared.FloodgateManagement;
+
import java.net.InetSocketAddress;
import java.util.UUID;
@@ -33,11 +38,6 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
-import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
-import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
-import com.github.games647.fastlogin.core.shared.FastLoginCore;
-import com.github.games647.fastlogin.core.shared.FloodgateManagement;
-
public class FloodgateAuthTask extends FloodgateManagement<Player, CommandSender, BukkitLoginSession, FastLoginBukkit> {
public FloodgateAuthTask(FastLoginCore<Player, CommandSender, FastLoginBukkit> core, Player player, FloodgatePlayer floodgatePlayer) {
diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/event/BungeeFastLoginAutoLoginEvent.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/event/BungeeFastLoginAutoLoginEvent.java
index 365a198..6503ff9 100644
--- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/event/BungeeFastLoginAutoLoginEvent.java
+++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/event/BungeeFastLoginAutoLoginEvent.java
@@ -28,6 +28,7 @@ package com.github.games647.fastlogin.bungee.event;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSession;
import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent;
+
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.api.plugin.Event;
diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/event/BungeeFastLoginPreLoginEvent.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/event/BungeeFastLoginPreLoginEvent.java
index b350763..2128cab 100644
--- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/event/BungeeFastLoginPreLoginEvent.java
+++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/event/BungeeFastLoginPreLoginEvent.java
@@ -28,6 +28,7 @@ package com.github.games647.fastlogin.bungee.event;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSource;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
+
import net.md_5.bungee.api.plugin.Event;
public class BungeeFastLoginPreLoginEvent extends Event implements FastLoginPreLoginEvent {
diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/task/AsyncToggleMessage.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/task/AsyncToggleMessage.java
index 98c384c..2965855 100644
--- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/task/AsyncToggleMessage.java
+++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/task/AsyncToggleMessage.java
@@ -29,8 +29,8 @@ import com.github.games647.fastlogin.bungee.FastLoginBungee;
import com.github.games647.fastlogin.bungee.event.BungeeFastLoginPremiumToggleEvent;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.FastLoginCore;
-
import com.github.games647.fastlogin.core.shared.event.FastLoginPremiumToggleEvent.PremiumToggleReason;
+
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.TextComponent;
diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/task/FloodgateAuthTask.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/task/FloodgateAuthTask.java
index 72719cf..5133198 100644
--- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/task/FloodgateAuthTask.java
+++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/task/FloodgateAuthTask.java
@@ -25,19 +25,19 @@
*/
package com.github.games647.fastlogin.bungee.task;
+import com.github.games647.fastlogin.bungee.BungeeLoginSession;
+import com.github.games647.fastlogin.bungee.FastLoginBungee;
+import com.github.games647.fastlogin.core.shared.FastLoginCore;
+import com.github.games647.fastlogin.core.shared.FloodgateManagement;
+
import java.net.InetSocketAddress;
import java.util.UUID;
-import org.geysermc.floodgate.api.player.FloodgatePlayer;
-
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.Server;
-import com.github.games647.fastlogin.bungee.BungeeLoginSession;
-import com.github.games647.fastlogin.bungee.FastLoginBungee;
-import com.github.games647.fastlogin.core.shared.FastLoginCore;
-import com.github.games647.fastlogin.core.shared.FloodgateManagement;
+import org.geysermc.floodgate.api.player.FloodgatePlayer;
public class FloodgateAuthTask
extends FloodgateManagement<ProxiedPlayer, CommandSender, BungeeLoginSession, FastLoginBungee> {
diff --git a/core/src/main/java/com/github/games647/fastlogin/core/hooks/DefaultPasswordGenerator.java b/core/src/main/java/com/github/games647/fastlogin/core/hooks/DefaultPasswordGenerator.java
index b6802a6..9caadef 100644
--- a/core/src/main/java/com/github/games647/fastlogin/core/hooks/DefaultPasswordGenerator.java
+++ b/core/src/main/java/com/github/games647/fastlogin/core/hooks/DefaultPasswordGenerator.java
@@ -26,7 +26,7 @@
package com.github.games647.fastlogin.core.hooks;
import java.security.SecureRandom;
-import java.util.Random;
+import java.util.random.RandomGenerator;
import java.util.stream.IntStream;
public class DefaultPasswordGenerator<P> implements PasswordGenerator<P> {
@@ -35,7 +35,7 @@ public class DefaultPasswordGenerator<P> implements PasswordGenerator<P> {
private static final char[] PASSWORD_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
.toCharArray();
- private final Random random = new SecureRandom();
+ private final RandomGenerator random = new SecureRandom();
@Override
public String getRandomPassword(P player) {
diff --git a/core/src/main/java/com/github/games647/fastlogin/core/hooks/bedrock/FloodgateService.java b/core/src/main/java/com/github/games647/fastlogin/core/hooks/bedrock/FloodgateService.java
index 7e6a1c2..1b555f1 100644
--- a/core/src/main/java/com/github/games647/fastlogin/core/hooks/bedrock/FloodgateService.java
+++ b/core/src/main/java/com/github/games647/fastlogin/core/hooks/bedrock/FloodgateService.java
@@ -54,14 +54,13 @@ public class FloodgateService extends BedrockService<FloodgatePlayer> {
* <li>autoLoginFloodgate
* <li>autoRegisterFloodgate
* </ul>
- * </p>
*
* @param key the key of the entry in config.yml
* @return <b>true</b> if the entry's value is "true", "false", or "linked"
*/
public boolean isValidFloodgateConfigString(String key) {
String value = core.getConfig().get(key).toString().toLowerCase(Locale.ENGLISH);
- if (!value.equals("true") && !value.equals("linked") && !value.equals("false") && !value.equals("no-conflict")) {
+ if (!"true".equals(value) && !"linked".equals(value) && !"false".equals(value) && !"no-conflict".equals(value)) {
core.getPlugin().getLog().error("Invalid value detected for {} in FastLogin/config.yml.", key);
return false;
}
@@ -87,7 +86,7 @@ public class FloodgateService extends BedrockService<FloodgatePlayer> {
} else {
core.getPlugin().getLog().info("Skipping name conflict checking for player {}", username);
}
-
+
//Floodgate users don't need Java specific checks
return true;
}
@@ -98,7 +97,7 @@ public class FloodgateService extends BedrockService<FloodgatePlayer> {
* username can be found
* <br>
* <i>Falls back to non-prefixed name checks, if ProtocolLib is installed</i>
- *
+ *
* @param prefixedUsername the name of the player with the prefix appended
* @return FloodgatePlayer if found, null otherwise
*/
diff --git a/core/src/main/java/com/github/games647/fastlogin/core/shared/ForceLoginManagement.java b/core/src/main/java/com/github/games647/fastlogin/core/shared/ForceLoginManagement.java
index c8c7bea..873a855 100644
--- a/core/src/main/java/com/github/games647/fastlogin/core/shared/ForceLoginManagement.java
+++ b/core/src/main/java/com/github/games647/fastlogin/core/shared/ForceLoginManagement.java
@@ -25,10 +25,10 @@
*/
package com.github.games647.fastlogin.core.shared;
-import com.github.games647.fastlogin.core.storage.SQLStorage;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.shared.event.FastLoginAutoLoginEvent;
+import com.github.games647.fastlogin.core.storage.SQLStorage;
public abstract class ForceLoginManagement<P extends C, C, L extends LoginSession, T extends PlatformPlugin<C>>
implements Runnable {
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 3f753cd..34f196a 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
@@ -32,8 +32,8 @@ import java.util.concurrent.TimeUnit;
import org.junit.Test;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
public class TickingRateLimiterTest {
@@ -43,7 +43,7 @@ public class TickingRateLimiterTest {
* Always expired
*/
@Test
- public void allowExpire() throws InterruptedException {
+ public void allowExpire() {
int size = 3;
FakeTicker ticker = new FakeTicker(5_000_000L);
@@ -51,17 +51,17 @@ public class TickingRateLimiterTest {
// run twice the size to fill it first and then test it
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, size, 0);
for (int i = 0; i < size; i++) {
- assertTrue("Filling up", rateLimiter.tryAcquire());
+ assertThat("Filling up", rateLimiter.tryAcquire(), is(true));
}
for (int i = 0; i < size; i++) {
ticker.add(Duration.ofSeconds(1));
- assertTrue("Should be expired", rateLimiter.tryAcquire());
+ assertThat("Should be expired", rateLimiter.tryAcquire(), is(true));
}
}
@Test
- public void allowExpireNegative() throws InterruptedException {
+ public void allowExpireNegative() {
int size = 3;
FakeTicker ticker = new FakeTicker(-5_000_000L);
@@ -69,12 +69,12 @@ public class TickingRateLimiterTest {
// run twice the size to fill it first and then test it
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, size, 0);
for (int i = 0; i < size; i++) {
- assertTrue("Filling up", rateLimiter.tryAcquire());
+ assertThat("Filling up", rateLimiter.tryAcquire(), is(true));
}
for (int i = 0; i < size; i++) {
ticker.add(Duration.ofSeconds(1));
- assertTrue("Should be expired", rateLimiter.tryAcquire());
+ assertThat("Should be expired", rateLimiter.tryAcquire(), is(true));
}
}
@@ -90,10 +90,10 @@ public class TickingRateLimiterTest {
// fill the size
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, size, TimeUnit.SECONDS.toMillis(30));
for (int i = 0; i < size; i++) {
- assertTrue("Filling up", rateLimiter.tryAcquire());
+ assertThat("Filling up", rateLimiter.tryAcquire(), is(true));
}
- assertFalse("Should be full and no entry should be expired", rateLimiter.tryAcquire());
+ assertThat("Should be full and no entry should be expired", rateLimiter.tryAcquire(), is(false));
}
/**
@@ -108,51 +108,51 @@ public class TickingRateLimiterTest {
// fill the size
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, size, TimeUnit.SECONDS.toMillis(30));
for (int i = 0; i < size; i++) {
- assertTrue("Filling up", rateLimiter.tryAcquire());
+ assertThat("Filling up", rateLimiter.tryAcquire(), is(true));
}
- assertFalse("Should be full and no entry should be expired", rateLimiter.tryAcquire());
+ assertThat("Should be full and no entry should be expired", rateLimiter.tryAcquire(), is(false));
}
/**
* Blocked attempts shouldn't replace existing ones.
*/
@Test
- public void blockedNotAdded() throws InterruptedException {
+ public void blockedNotAdded() {
FakeTicker ticker = new FakeTicker(5_000_000L);
// fill the size - 100ms should be reasonable high
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, 1, 100);
- assertTrue("Filling up", rateLimiter.tryAcquire());
+ assertThat("Filling up", rateLimiter.tryAcquire(), is(true));
ticker.add(Duration.ofMillis(50));
// still is full - should fail
- assertFalse("Expired too early", rateLimiter.tryAcquire());
+ assertThat("Expired too early", rateLimiter.tryAcquire(), is(false));
// wait the remaining time and add a threshold, because
ticker.add(Duration.ofMillis(50));
- assertTrue("Request not released", rateLimiter.tryAcquire());
+ assertThat("Request not released", rateLimiter.tryAcquire(), is(true));
}
/**
* Blocked attempts shouldn't replace existing ones.
*/
@Test
- public void blockedNotAddedNegative() throws InterruptedException {
+ public void blockedNotAddedNegative() {
FakeTicker ticker = new FakeTicker(-5_000_000L);
// fill the size - 100ms should be reasonable high
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, 1, 100);
- assertTrue("Filling up", rateLimiter.tryAcquire());
+ assertThat("Filling up", rateLimiter.tryAcquire(), is(true));
ticker.add(Duration.ofMillis(50));
// still is full - should fail
- assertFalse("Expired too early", rateLimiter.tryAcquire());
+ assertThat("Expired too early", rateLimiter.tryAcquire(), is(false));
// wait the remaining time and add a threshold, because
ticker.add(Duration.ofMillis(50));
- assertTrue("Request not released", rateLimiter.tryAcquire());
+ assertThat("Request not released", rateLimiter.tryAcquire(), is(true));
}
}
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 33c8c31..902fb03 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
@@ -45,9 +45,11 @@ import com.velocitypowered.api.proxy.InboundConnection;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.util.GameProfile;
+import com.velocitypowered.api.util.GameProfile.Property;
import java.net.InetSocketAddress;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@@ -121,7 +123,7 @@ public class ConnectListener {
}
}
- private List<GameProfile.Property> removeSkin(List<GameProfile.Property> oldProperties) {
+ private List<GameProfile.Property> removeSkin(Collection<Property> oldProperties) {
List<GameProfile.Property> newProperties = new ArrayList<>(oldProperties.size() - 1);
for (GameProfile.Property property : oldProperties) {
if (!"textures".equals(property.getName()))
diff --git a/velocity/src/main/java/com/github/games647/fastlogin/velocity/task/AsyncToggleMessage.java b/velocity/src/main/java/com/github/games647/fastlogin/velocity/task/AsyncToggleMessage.java
index 12444fc..8dc7d1c 100644
--- a/velocity/src/main/java/com/github/games647/fastlogin/velocity/task/AsyncToggleMessage.java
+++ b/velocity/src/main/java/com/github/games647/fastlogin/velocity/task/AsyncToggleMessage.java
@@ -32,6 +32,7 @@ import com.github.games647.fastlogin.velocity.FastLoginVelocity;
import com.github.games647.fastlogin.velocity.event.VelocityFastLoginPremiumToggleEvent;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player;
+
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
public class AsyncToggleMessage implements Runnable {
|
||
|
|
b041a89209 | Typo fixes | ||
|
|
a5942cba74 | Use HTML links | ||
|
|
f44d7a6780 |
Forward client key to server
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 a3bb3d0..55a8f33 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
@@ -119,7 +119,7 @@ public class ProtocolLibListener extends PacketAdapter {
case Continue:
default:
//player.getName() won't work at this state
- onLogin(packetEvent, sender, username);
+ onLoginStart(packetEvent, sender, username);
break;
}
} else {
@@ -146,7 +146,6 @@ public class ProtocolLibListener extends PacketAdapter {
long salt = FuzzyReflection.getFieldValue(signatureData, Long.TYPE, true);
byte[] signature = FuzzyReflection.getFieldValue(signatureData, byte[].class, true);
- BukkitLoginSession session = plugin.getSession(sender.getAddress());
PublicKey publicKey = session.getClientPublicKey().getKey();
try {
if (EncryptionUtil.verifySignedNonce(session.getVerifyToken(), publicKey, salt, signature)) {
@@ -162,7 +161,7 @@ public class ProtocolLibListener extends PacketAdapter {
}
}
- private void onLogin(PacketEvent packetEvent, Player player, String username) {
+ private void onLoginStart(PacketEvent packetEvent, Player player, String username) {
//this includes ip:port. Should be unique for an incoming login request with a timeout of 2 minutes
String sessionKey = player.getAddress().toString();
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 d13a5c9..ed84298 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
@@ -43,6 +43,7 @@ import com.github.games647.craftapi.model.skin.SkinProperty;
import com.github.games647.craftapi.resolver.MojangResolver;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
+import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
import java.io.IOException;
import java.lang.reflect.Method;
@@ -168,7 +169,7 @@ public class VerifyResponseTask implements Runnable {
session.setVerified(true);
setPremiumUUID(session.getUuid());
- receiveFakeStartPacket(realUsername);
+ receiveFakeStartPacket(realUsername, session.getClientPublicKey());
}
private void setPremiumUUID(UUID premiumUUID) {
@@ -253,7 +254,7 @@ public class VerifyResponseTask implements Runnable {
}
//fake a new login packet in order to let the server handle all the other stuff
- private void receiveFakeStartPacket(String username) {
+ private void receiveFakeStartPacket(String username, ClientPublicKey clientKey) {
//see StartPacketListener for packet information
PacketContainer startPacket = new PacketContainer(START);
@@ -261,7 +262,8 @@ public class VerifyResponseTask implements Runnable {
startPacket.getStrings().write(0, username);
EquivalentConverter<WrappedProfileKeyData> converter = BukkitConverters.getWrappedPublicKeyDataConverter();
- startPacket.getOptionals(converter).write(0, Optional.empty());
+ var key = new WrappedProfileKeyData(clientKey.getExpiry(), clientKey.getKey(), sharedSecret);
+ startPacket.getOptionals(converter).write(0, Optional.of(key));
} else {
//uuid is ignored by the packet definition
WrappedGameProfile fakeProfile = new WrappedGameProfile(UUID.randomUUID(), username);
|
||
|
|
0f17fe18f9 | Document origin of signing keys | ||
|
|
dac5cd7639 |
Verify signed nonce
diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index 9b3c5c5..c1f63ba 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -179,6 +179,19 @@
<version>1.0.7</version>
</dependency>
+ <dependency>
+ <groupId>com.mojang</groupId>
+ <artifactId>datafixerupper</artifactId>
+ <version>5.0.28</version>
+ <scope>provided</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
<!--Library for listening and sending Minecraft packets-->
<dependency>
<groupId>com.comphenix.protocol</groupId>
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java
index 556def1..4f4af4d 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java
@@ -26,6 +26,7 @@
package com.github.games647.fastlogin.bukkit;
import com.github.games647.craftapi.model.skin.SkinProperty;
+import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.LoginSession;
@@ -42,30 +43,33 @@ public class BukkitLoginSession extends LoginSession {
private final byte[] verifyToken;
+ private final ClientPublicKey clientPublicKey;
+
private boolean verified;
private SkinProperty skinProperty;
- public BukkitLoginSession(String username, byte[] verifyToken, boolean registered
+ public BukkitLoginSession(String username, byte[] verifyToken, ClientPublicKey publicKey, boolean registered
, StoredProfile profile) {
super(username, registered, profile);
+ this.clientPublicKey = publicKey;
this.verifyToken = verifyToken.clone();
}
//available for BungeeCord
public BukkitLoginSession(String username, boolean registered) {
- this(username, EMPTY_ARRAY, registered, null);
+ this(username, EMPTY_ARRAY, null, registered, null);
}
//cracked player
public BukkitLoginSession(String username, StoredProfile profile) {
- this(username, EMPTY_ARRAY, false, profile);
+ this(username, EMPTY_ARRAY, null, false, profile);
}
//ProtocolSupport
public BukkitLoginSession(String username, boolean registered, StoredProfile profile) {
- this(username, EMPTY_ARRAY, registered, profile);
+ this(username, EMPTY_ARRAY, null, registered, profile);
}
/**
@@ -79,6 +83,10 @@ public class BukkitLoginSession extends LoginSession {
return verifyToken.clone();
}
+ public ClientPublicKey getClientPublicKey() {
+ return clientPublicKey;
+ }
+
/**
* @return premium skin if available
*/
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java
index 956a60f..713fa68 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java
@@ -27,6 +27,7 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
import com.google.common.io.Resources;
+import com.google.common.primitives.Longs;
import java.io.IOException;
import java.math.BigInteger;
@@ -115,9 +116,9 @@ class EncryptionUtil {
/**
* Generate the server id based on client and server data.
*
- * @param sessionId session for the current login attempt
+ * @param sessionId session for the current login attempt
* @param sharedSecret shared secret between the client and the server
- * @param publicKey public key of the server
+ * @param publicKey public key of the server
* @return the server id formatted as a hexadecimal string.
*/
public static String getServerIdHashString(String sessionId, SecretKey sharedSecret, PublicKey publicKey) {
@@ -136,7 +137,7 @@ class EncryptionUtil {
* Decrypts the content and extracts the key spec.
*
* @param privateKey private server key
- * @param sharedKey the encrypted shared key
+ * @param sharedKey the encrypted shared key
* @return shared secret key
* @throws GeneralSecurityException if it fails to decrypt the data
*/
@@ -151,10 +152,20 @@ class EncryptionUtil {
return false;
}
- Signature signature = Signature.getInstance("SHA1withRSA");
- signature.initVerify(mojangSessionKey);
- signature.update(toSignable(clientKey).getBytes(StandardCharsets.US_ASCII));
- return signature.verify(clientKey.getSignature());
+ Signature verifier = Signature.getInstance("SHA1withRSA");
+ verifier.initVerify(mojangSessionKey);
+ verifier.update(toSignable(clientKey).getBytes(StandardCharsets.US_ASCII));
+ return verifier.verify(clientKey.getSignature());
+ }
+
+ public static boolean verifySignedNonce(byte[] nonce, PublicKey clientKey, long signatureSalt, byte[] signature)
+ throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ Signature verifier = Signature.getInstance("SHA256withRSA");
+ verifier.initVerify(clientKey);
+
+ verifier.update(nonce);
+ verifier.update(Longs.toByteArray(signatureSalt));
+ return verifier.verify(signature);
}
private static PublicKey loadMojangSessionKey()
@@ -183,7 +194,7 @@ class EncryptionUtil {
* Decrypted the given data using the cipher.
*
* @param cipher decryption cypher initialized with the private key
- * @param data the encrypted data
+ * @param data the encrypted data
* @return clear text data
* @throws GeneralSecurityException if it fails to decrypt the data
*/
@@ -194,7 +205,7 @@ class EncryptionUtil {
}
private static byte[] getServerIdHash(String sessionId, PublicKey publicKey, SecretKey sharedSecret)
- throws NoSuchAlgorithmException {
+ throws NoSuchAlgorithmException {
// byte[] a(String var0, PublicKey var1, SecretKey var2)
MessageDigest digest = MessageDigest.getInstance("SHA-1");
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 f0a4083..485c065 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
@@ -27,21 +27,25 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketEvent;
+import com.comphenix.protocol.wrappers.BukkitConverters;
+import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPreLoginEvent;
+import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.JoinManagement;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import java.security.PublicKey;
+import java.util.Optional;
import java.util.Random;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class NameCheckTask extends JoinManagement<Player, CommandSender, ProtocolLibLoginSource>
- implements Runnable {
+ implements Runnable {
private final FastLoginBukkit plugin;
private final PacketEvent packetEvent;
@@ -67,7 +71,9 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
@Override
public void run() {
try {
- super.onLogin(username, new ProtocolLibLoginSource(player, random, publicKey));
+ Optional<WrappedProfileKeyData> publicKey = packetEvent.getPacket().getOptionals(BukkitConverters.getWrappedPublicKeyDataConverter()).read(0);
+
+ super.onLogin(username, new ProtocolLibLoginSource(player, random, publicKey.get(), this.publicKey));
} finally {
ProtocolLibrary.getProtocolManager().getAsynchronousManager().signalPacketTransmission(packetEvent);
}
@@ -85,7 +91,7 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L161
@Override
public void requestPremiumLogin(ProtocolLibLoginSource source, StoredProfile profile
- , String username, boolean registered) {
+ , String username, boolean registered) {
try {
source.enableOnlinemode();
} catch (Exception ex) {
@@ -97,8 +103,10 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
core.getPendingLogin().put(ip + username, new Object());
byte[] verify = source.getVerifyToken();
+ WrappedProfileKeyData key = source.getClientPublicKey();
+ ClientPublicKey clientKey = new ClientPublicKey(key.getExpireTime(), key.getKey(), key.getSignature());
- BukkitLoginSession playerSession = new BukkitLoginSession(username, verify, registered, profile);
+ BukkitLoginSession playerSession = new BukkitLoginSession(username, verify, clientKey, registered, profile);
plugin.putSession(player.getAddress(), playerSession);
//cancel only if the player has a paid account otherwise login as normal offline player
synchronized (packetEvent.getAsyncMarker().getProcessingLock()) {
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 27c0335..a3bb3d0 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.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.comphenix.protocol.wrappers.WrappedProfilePublicKey;
import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
@@ -38,6 +39,7 @@ import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
import com.github.games647.fastlogin.core.antibot.AntiBotService;
import com.github.games647.fastlogin.core.antibot.AntiBotService.Action;
+import com.mojang.datafixers.util.Either;
import java.net.InetSocketAddress;
import java.security.InvalidKeyException;
@@ -139,9 +141,24 @@ public class ProtocolLibListener extends PacketAdapter {
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);
+ Either<byte[], ?> either = packetEvent.getPacket().getSpecificModifier(Either.class).read(0);
+ Object signatureData = either.right().get();
+ long salt = FuzzyReflection.getFieldValue(signatureData, Long.TYPE, true);
+ byte[] signature = FuzzyReflection.getFieldValue(signatureData, byte[].class, true);
+
+ BukkitLoginSession session = plugin.getSession(sender.getAddress());
+ PublicKey publicKey = session.getClientPublicKey().getKey();
+ try {
+ if (EncryptionUtil.verifySignedNonce(session.getVerifyToken(), publicKey, salt, signature)) {
+ packetEvent.getAsyncMarker().incrementProcessingDelay();
+ Runnable verifyTask = new VerifyResponseTask(plugin, packetEvent, sender, sharedSecret, keyPair);
+ plugin.getScheduler().runAsync(verifyTask);
+ } else {
+ sender.kickPlayer("Invalid signature");
+ }
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ sender.kickPlayer("Invalid signature");
+ }
}
}
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java
index dd191f1..d87b602 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java
@@ -30,6 +30,7 @@ import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
+import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
import com.github.games647.fastlogin.core.shared.LoginSource;
import java.lang.reflect.InvocationTargetException;
@@ -48,15 +49,18 @@ class ProtocolLibLoginSource implements LoginSource {
private final Player player;
private final Random random;
+
+ private final WrappedProfileKeyData clientPublicKey;
private final PublicKey publicKey;
private final String serverId = "";
private byte[] verifyToken;
- public ProtocolLibLoginSource(Player player, Random random, PublicKey publicKey) {
+ public ProtocolLibLoginSource(Player player, Random random, WrappedProfileKeyData clientPublicKey, PublicKey serverPublicKey) {
this.player = player;
this.random = random;
- this.publicKey = publicKey;
+ this.clientPublicKey = clientPublicKey;
+ this.publicKey = serverPublicKey;
}
@Override
@@ -109,6 +113,10 @@ class ProtocolLibLoginSource implements LoginSource {
return player.getAddress();
}
+ public WrappedProfileKeyData getClientPublicKey() {
+ return clientPublicKey;
+ }
+
public String getServerId() {
return serverId;
}
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 e974b09..d13a5c9 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
@@ -29,12 +29,15 @@ import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.temporary.TemporaryPlayerFactory;
+import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
+import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
+import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
import com.github.games647.craftapi.model.auth.Verification;
import com.github.games647.craftapi.model.skin.SkinProperty;
import com.github.games647.craftapi.resolver.MojangResolver;
@@ -120,7 +123,7 @@ public class VerifyResponseTask implements Runnable {
}
try {
- if (!checkVerifyToken(session) || !enableEncryption(loginKey)) {
+ if (!enableEncryption(loginKey)) {
return;
}
} catch (Exception ex) {
@@ -180,23 +183,6 @@ public class VerifyResponseTask implements Runnable {
}
}
- private boolean checkVerifyToken(BukkitLoginSession session) throws GeneralSecurityException {
- byte[] requestVerify = session.getVerifyToken();
- //encrypted verify token
- byte[] responseVerify = packetEvent.getPacket().getByteArrays().read(1);
-
- //https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L182
- if (!Arrays.equals(requestVerify, EncryptionUtil.decrypt(serverKey.getPrivate(), responseVerify))) {
- //check if the verify-token are equal to the server sent one
- disconnect("invalid-verify-token",
- "GameProfile {0} ({1}) tried to login with an invalid verify token. Server: {2} Client: {3}",
- session.getRequestUsername(), packetEvent.getPlayer().getAddress(), requestVerify, responseVerify);
- return false;
- }
-
- return true;
- }
-
//try to get the networkManager from ProtocolLib
private Object getNetworkManager() throws IllegalAccessException, ClassNotFoundException {
Object injectorContainer = TemporaryPlayerFactory.getInjectorFromPlayer(player);
@@ -273,6 +259,9 @@ public class VerifyResponseTask implements Runnable {
if (MinecraftVersion.atOrAbove(new MinecraftVersion(1, 19, 0))) {
startPacket.getStrings().write(0, username);
+
+ EquivalentConverter<WrappedProfileKeyData> converter = BukkitConverters.getWrappedPublicKeyDataConverter();
+ startPacket.getOptionals(converter).write(0, Optional.empty());
} else {
//uuid is ignored by the packet definition
WrappedGameProfile fakeProfile = new WrappedGameProfile(UUID.randomUUID(), username);
diff --git a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/Base64Adapter.java b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/Base64Adapter.java
new file mode 100644
index 0000000..c2a2d1a
--- /dev/null
+++ b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/Base64Adapter.java
@@ -0,0 +1,48 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2022 games647 and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.games647.fastlogin.bukkit.listener.protocollib;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+import java.util.Base64;
+
+public class Base64Adapter extends TypeAdapter<byte[]> {
+
+ @Override
+ public void write(JsonWriter out, byte[] value) throws IOException {
+ var encoded = Base64.getEncoder().encodeToString(value);
+ out.value(encoded);
+ }
+
+ @Override
+ public byte[] read(JsonReader in) throws IOException {
+ String encoded = in.nextString();
+ return Base64.getDecoder().decode(encoded);
+ }
+}
diff --git a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java
index 904405a..63a24ba 100644
--- a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java
+++ b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java
@@ -25,6 +25,7 @@
*/
package com.github.games647.fastlogin.bukkit.listener.protocollib;
+import com.github.games647.fastlogin.bukkit.listener.protocollib.SignatureTestData.SignatureData;
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
import com.google.common.io.Resources;
import com.google.gson.Gson;
@@ -36,9 +37,12 @@ import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
import java.security.SecureRandom;
+import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
@@ -65,7 +69,7 @@ public class EncryptionUtilTest {
@Test
public void testExpiredClientKey() throws Exception {
- var clientKey = loadClientKey("client_keys/valid.json");
+ var clientKey = loadClientKey("client_keys/valid_public_key.json");
// Client expires at the exact second mentioned, so use it for verification
var expiredTimestamp = clientKey.getExpiry();
@@ -78,7 +82,9 @@ public class EncryptionUtilTest {
// expiration date changed should make the signature invalid
// expiration should still be valid
var clientKey = loadClientKey("client_keys/invalid_wrong_expiration.json");
- assertThat(EncryptionUtil.verifyClientKey(clientKey, clientKey.getExpiry().minus(5, ChronoUnit.HOURS)), is(false));
+ Instant expireTimestamp = clientKey.getExpiry().minus(5, ChronoUnit.HOURS);
+
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, expireTimestamp), is(false));
}
// @Test(expected = Exception.class)
@@ -86,31 +92,119 @@ public class EncryptionUtilTest {
public void testInvalidChangedKey() throws Exception {
// changed public key no longer corresponding to the signature
var clientKey = loadClientKey("client_keys/invalid_wrong_key.json");
- assertThat(EncryptionUtil.verifyClientKey(clientKey, clientKey.getExpiry().minus(5, ChronoUnit.HOURS)), is(false));
+ Instant expireTimestamp = clientKey.getExpiry().minus(5, ChronoUnit.HOURS);
+
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, expireTimestamp), is(false));
}
@Test
public void testInvalidChangedSignature() throws Exception {
// signature modified no longer corresponding to key and expiration date
var clientKey = loadClientKey("client_keys/invalid_wrong_signature.json");
- assertThat(EncryptionUtil.verifyClientKey(clientKey, clientKey.getExpiry().minus(5, ChronoUnit.HOURS)), is(false));
+ Instant expireTimestamp = clientKey.getExpiry().minus(5, ChronoUnit.HOURS);
+
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, expireTimestamp), is(false));
}
@Test
public void testValidClientKey() throws Exception {
- var clientKey = loadClientKey("client_keys/valid.json");
-
+ var clientKey = loadClientKey("client_keys/valid_public_key.json");
var verificationTimestamp = clientKey.getExpiry().minus(5, ChronoUnit.HOURS);
+
assertThat(EncryptionUtil.verifyClientKey(clientKey, verificationTimestamp), is(true));
}
+ @Test
+ public void testValidSignedNonce() throws Exception {
+ ClientPublicKey clientKey = loadClientKey("client_keys/valid_public_key.json");
+ PublicKey clientPublicKey = clientKey.getKey();
+
+ SignatureTestData testData = loadSignatureResource("signature/valid_signature.json");
+ byte[] nonce = testData.getNonce();
+ SignatureData signature = testData.getSignature();
+ long salt = signature.getSalt();
+ assertThat(EncryptionUtil.verifySignedNonce(nonce, clientPublicKey, salt, signature.getSignature()), is(true));
+ }
+
+ @Test
+ public void testIncorrectNonce() throws Exception {
+ ClientPublicKey clientKey = loadClientKey("client_keys/valid_public_key.json");
+ PublicKey clientPublicKey = clientKey.getKey();
+
+ SignatureTestData testData = loadSignatureResource("signature/incorrect_nonce.json");
+ byte[] nonce = testData.getNonce();
+ SignatureData signature = testData.getSignature();
+ long salt = signature.getSalt();
+ assertThat(EncryptionUtil.verifySignedNonce(nonce, clientPublicKey, salt, signature.getSignature()), is(false));
+ }
+
+ @Test
+ public void testIncorrectSalt() throws Exception {
+ // client generated
+ ClientPublicKey clientKey = loadClientKey("client_keys/valid_public_key.json");
+ PublicKey clientPublicKey = clientKey.getKey();
+
+ SignatureTestData testData = loadSignatureResource("signature/incorrect_salt.json");
+ byte[] nonce = testData.getNonce();
+ SignatureData signature = testData.getSignature();
+ long salt = signature.getSalt();
+ assertThat(EncryptionUtil.verifySignedNonce(nonce, clientPublicKey, salt, signature.getSignature()), is(false));
+ }
+
+ @Test
+ public void testIncorrectSignature() throws Exception {
+ // client generated
+ ClientPublicKey clientKey = loadClientKey("client_keys/valid_public_key.json");
+ PublicKey clientPublicKey = clientKey.getKey();
+
+ SignatureTestData testData = loadSignatureResource("signature/incorrect_signature.json");
+ byte[] nonce = testData.getNonce();
+ SignatureData signature = testData.getSignature();
+ long salt = signature.getSalt();
+ assertThat(EncryptionUtil.verifySignedNonce(nonce, clientPublicKey, salt, signature.getSignature()), is(false));
+ }
+
+ @Test
+ public void testWrongPublicKeySigned() throws Exception {
+ // load a different public key
+ ClientPublicKey clientKey = loadClientKey("client_keys/invalid_wrong_key.json");
+ PublicKey clientPublicKey = clientKey.getKey();
+
+ SignatureTestData testData = loadSignatureResource("signature/valid_signature.json");
+ byte[] nonce = testData.getNonce();
+ SignatureData signature = testData.getSignature();
+ long salt = signature.getSalt();
+ assertThat(EncryptionUtil.verifySignedNonce(nonce, clientPublicKey, salt, signature.getSignature()), is(false));
+ }
+
+ private SignatureTestData loadSignatureResource(String resourceName) throws IOException {
+ var keyUrl = Resources.getResource(resourceName);
+ var encodedSignature = Resources.toString(keyUrl, StandardCharsets.US_ASCII);
+
+ return new Gson().fromJson(encodedSignature, SignatureTestData.class);
+ }
+
+ private RSAPrivateKey parsePrivateKey(String keySpec)
+ throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
+ try (
+ Reader reader = new StringReader(keySpec);
+ PemReader pemReader = new PemReader(reader)
+ ) {
+ PemObject pemObject = pemReader.readPemObject();
+ byte[] content = pemObject.getContent();
+ var privateKeySpec = new PKCS8EncodedKeySpec(content);
+
+ var factory = KeyFactory.getInstance("RSA");
+ return (RSAPrivateKey) factory.generatePrivate(privateKeySpec);
+ }
+ }
+
private ClientPublicKey loadClientKey(String path)
throws NoSuchAlgorithmException, IOException, InvalidKeySpecException {
var keyUrl = Resources.getResource(path);
- var gson = new Gson();
var lines = Resources.toString(keyUrl, StandardCharsets.US_ASCII);
- var object = gson.fromJson(lines, JsonObject.class);
+ var object = new Gson().fromJson(lines, JsonObject.class);
Instant expires = Instant.parse(object.getAsJsonPrimitive("expires_at").getAsString());
String key = object.getAsJsonPrimitive("key").getAsString();
@@ -120,10 +214,10 @@ public class EncryptionUtilTest {
return new ClientPublicKey(expires, publicKey, signature);
}
- private RSAPublicKey parsePublicKey(String lines)
+ private RSAPublicKey parsePublicKey(String keySpec)
throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
try (
- Reader reader = new StringReader(lines);
+ Reader reader = new StringReader(keySpec);
PemReader pemReader = new PemReader(reader)
) {
PemObject pemObject = pemReader.readPemObject();
diff --git a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SignatureTestData.java b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SignatureTestData.java
new file mode 100644
index 0000000..8ea85f6
--- /dev/null
+++ b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/SignatureTestData.java
@@ -0,0 +1,60 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2022 games647 and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.games647.fastlogin.bukkit.listener.protocollib;
+
+import com.google.gson.annotations.JsonAdapter;
+
+public class SignatureTestData {
+
+ @JsonAdapter(Base64Adapter.class)
+ private byte[] nonce;
+
+ private SignatureData signature;
+
+ public byte[] getNonce() {
+ return nonce;
+ }
+
+ public SignatureData getSignature() {
+ return signature;
+ }
+
+ public static class SignatureData {
+
+ private long salt;
+
+ @JsonAdapter(Base64Adapter.class)
+ private byte[] signature;
+
+ public long getSalt() {
+ return salt;
+ }
+
+ public byte[] getSignature() {
+ return signature;
+ }
+ }
+}
diff --git a/bukkit/src/test/resources/client_keys/README.md b/bukkit/src/test/resources/client_keys/README.md
new file mode 100644
index 0000000..1165e23
--- /dev/null
+++ b/bukkit/src/test/resources/client_keys/README.md
@@ -0,0 +1,27 @@
+# About
+
+This contains test resources for the unit tests. The file are extracted from the Minecraft directory with slight
+modifications. The files are found in `$MINECRAFT_HOME$/profilekeys/`, where `$MINECRAFT_HOME$` represents the
+OS-dependent minecraft folder.
+
+**Notable the files in this folder do not contain the private key information. It should be explicitly
+stripped before including it.**
+
+## Minecraft folder
+
+* Windows: `%appdata%\.minecraft`
+* Linux: `/home/username/.minecraft`
+* Mac: `~/Library/Application Support/minecraft`
+
+## Directory structure
+
+* `invalid_wrong_expiration.json`: Changed the expiration date
+* `invalid_wrong_key.json`: Modified public key while keeping the RSA structure valid
+* `invalid_wrong_signature.json`: Changed a character in the public key signature
+* `valid_public_key.json`: Extracted from actual file
+
+## File content
+
+* `expires_at`: Expiration date
+* `key`: Public key from the original file out of `public_key.key`
+* `signature`: Mojang signed signature of this public key
diff --git a/bukkit/src/test/resources/client_keys/invalid_wrong_expiration.json b/bukkit/src/test/resources/client_keys/invalid_wrong_expiration.json
index 7ecc12e..ea509fe 100644
--- a/bukkit/src/test/resources/client_keys/invalid_wrong_expiration.json
+++ b/bukkit/src/test/resources/client_keys/invalid_wrong_expiration.json
@@ -1,5 +1,5 @@
{
- "expires_at": "2022-06-12T09:46:26.421156927Z",
- "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU4I+xm\nDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/\n33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZ\nOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF\n4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWc\nPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
- "signature": "BYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
+ "expires_at": "2022-06-20T07:31:47.318722344Z",
+ "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApd3ZxDhcRWWru1XEBke6uYqmbnS2Oxyk\nOMj+QDKrkwUqhVJYciyXGsMx46Mgr/KIoGCcokP5OtIxc6+69/ZLqJ9PvM81kLIxAqyvfBMKMGjP\n376LgxTF1FeDpbe5zXaNRxfmnvQhS5YTLbzgk36qWVjqxJMG4VLVmh7RV5zWsb7XlckZb2zRHM2Y\nMHbEC+ggX+l6zQyfG1KK0MH5k+O6b0xD0rv1wm24sLOesTXH6RZG8cNE3ofdnavxjFodTOnra6w1\naiVcoUTdEPSS86wQwq9j0YCcAKOwMXsqbk9NhpujrdyJ94dev+ELwkNS7P0pPrcfiyFTQeJCZTXz\nJB36MwIDAQAB\n-----END RSA PUBLIC KEY-----\n",
+ "signature": "lfRXK4zL213wBKg760eiPV7yvnLZ6a6v9Iohmw78yxIzqXO3tfrC5Z+P2LGiO1BdI4xckx8yz4ktn82zX97+r2zktBw0As7g71H/FjInpoZ76j3gMUaiFNrQJ0vKCCI7xsjonemroWAVDCAqlvdyqwUu/Fnz85+WoR2kCQ721vwy6IjWA3xhq8XrWjkI/AlBmoS/kVqnvjjjc9vocdddJXbUYzCse/hWWIbsFeBXyiGCd3v7apgtXwQfM++tt87fq7444zQskiYb14oQP8/uNwqZWQ9jAs00i1BZ0MNM6+TZYGHOfS6rbHZ1bcX34VZdcCwpapK/Z2HBRIgDN4QOcgJkyq1GcjvlM2wjfhN8gXTsmbF9Ee+5Y6a4ONRkxRZK2sT8oAXdm0OlTEGB0P0+WRRFOQ/PnRqbI7lvANao2METT2EUHHrtqFMe53kqCHdzy5qyuHxdCEa6l/gSR08fybx9DdRRmhOlhSPGxhgwqyi1fEMrN4CsSKNrv5u+sMqhspA05b3DQJeLDX+UV5ujRHwm0A49NF+h1ZYlrcefz5IMUUisOOw6HiLc/YGLD2jHwSePGdfMwMnrIxbxjCta7/7A91aaN7eYm16KW9erCOwAfJmBSQC6Pbmg5f7rd7rAKVOPxglq7nayXmd+BK53Mal5tltMSgd/0iY6SEtGSEU="
}
diff --git a/bukkit/src/test/resources/client_keys/invalid_wrong_key.json b/bukkit/src/test/resources/client_keys/invalid_wrong_key.json
index 37bb3ad..98ea33f 100644
--- a/bukkit/src/test/resources/client_keys/invalid_wrong_key.json
+++ b/bukkit/src/test/resources/client_keys/invalid_wrong_key.json
@@ -1,5 +1,5 @@
{
- "expires_at": "2022-06-12T10:46:26.421156927Z",
+ "expires_at": "2022-06-20T08:31:47.318722344Z",
"key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU3I+xmDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWcPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
- "signature": "BYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
+ "signature": "lfRXK4zL213wBKg760eiPV7yvnLZ6a6v9Iohmw78yxIzqXO3tfrC5Z+P2LGiO1BdI4xckx8yz4ktn82zX97+r2zktBw0As7g71H/FjInpoZ76j3gMUaiFNrQJ0vKCCI7xsjonemroWAVDCAqlvdyqwUu/Fnz85+WoR2kCQ721vwy6IjWA3xhq8XrWjkI/AlBmoS/kVqnvjjjc9vocdddJXbUYzCse/hWWIbsFeBXyiGCd3v7apgtXwQfM++tt87fq7444zQskiYb14oQP8/uNwqZWQ9jAs00i1BZ0MNM6+TZYGHOfS6rbHZ1bcX34VZdcCwpapK/Z2HBRIgDN4QOcgJkyq1GcjvlM2wjfhN8gXTsmbF9Ee+5Y6a4ONRkxRZK2sT8oAXdm0OlTEGB0P0+WRRFOQ/PnRqbI7lvANao2METT2EUHHrtqFMe53kqCHdzy5qyuHxdCEa6l/gSR08fybx9DdRRmhOlhSPGxhgwqyi1fEMrN4CsSKNrv5u+sMqhspA05b3DQJeLDX+UV5ujRHwm0A49NF+h1ZYlrcefz5IMUUisOOw6HiLc/YGLD2jHwSePGdfMwMnrIxbxjCta7/7A91aaN7eYm16KW9erCOwAfJmBSQC6Pbmg5f7rd7rAKVOPxglq7nayXmd+BK53Mal5tltMSgd/0iY6SEtGSEU="
}
diff --git a/bukkit/src/test/resources/client_keys/invalid_wrong_signature.json b/bukkit/src/test/resources/client_keys/invalid_wrong_signature.json
index cbca4b1..2b80c2c 100644
--- a/bukkit/src/test/resources/client_keys/invalid_wrong_signature.json
+++ b/bukkit/src/test/resources/client_keys/invalid_wrong_signature.json
@@ -1,5 +1,5 @@
{
- "expires_at": "2022-06-12T10:46:26.421156927Z",
- "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU4I+xm\nDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/\n33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZ\nOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF\n4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWc\nPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
- "signature": "bYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
+ "expires_at": "2022-06-20T08:31:47.318722344Z",
+ "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApd3ZxDhcRWWru1XEBke6uYqmbnS2Oxyk\nOMj+QDKrkwUqhVJYciyXGsMx46Mgr/KIoGCcokP5OtIxc6+69/ZLqJ9PvM81kLIxAqyvfBMKMGjP\n376LgxTF1FeDpbe5zXaNRxfmnvQhS5YTLbzgk36qWVjqxJMG4VLVmh7RV5zWsb7XlckZb2zRHM2Y\nMHbEC+ggX+l6zQyfG1KK0MH5k+O6b0xD0rv1wm24sLOesTXH6RZG8cNE3ofdnavxjFodTOnra6w1\naiVcoUTdEPSS86wQwq9j0YCcAKOwMXsqbk9NhpujrdyJ94dev+ELwkNS7P0pPrcfiyFTQeJCZTXz\nJB36MwIDAQAB\n-----END RSA PUBLIC KEY-----\n",
+ "signature": "lfRxK4zL213wBKg760eiPV7yvnLZ6a6v9Iohmw78yxIzqXO3tfrC5Z+P2LGiO1BdI4xckx8yz4ktn82zX97+r2zktBw0As7g71H/FjInpoZ76j3gMUaiFNrQJ0vKCCI7xsjonemroWAVDCAqlvdyqwUu/Fnz85+WoR2kCQ721vwy6IjWA3xhq8XrWjkI/AlBmoS/kVqnvjjjc9vocdddJXbUYzCse/hWWIbsFeBXyiGCd3v7apgtXwQfM++tt87fq7444zQskiYb14oQP8/uNwqZWQ9jAs00i1BZ0MNM6+TZYGHOfS6rbHZ1bcX34VZdcCwpapK/Z2HBRIgDN4QOcgJkyq1GcjvlM2wjfhN8gXTsmbF9Ee+5Y6a4ONRkxRZK2sT8oAXdm0OlTEGB0P0+WRRFOQ/PnRqbI7lvANao2METT2EUHHrtqFMe53kqCHdzy5qyuHxdCEa6l/gSR08fybx9DdRRmhOlhSPGxhgwqyi1fEMrN4CsSKNrv5u+sMqhspA05b3DQJeLDX+UV5ujRHwm0A49NF+h1ZYlrcefz5IMUUisOOw6HiLc/YGLD2jHwSePGdfMwMnrIxbxjCta7/7A91aaN7eYm16KW9erCOwAfJmBSQC6Pbmg5f7rd7rAKVOPxglq7nayXmd+BK53Mal5tltMSgd/0iY6SEtGSEU="
}
diff --git a/bukkit/src/test/resources/client_keys/valid.json b/bukkit/src/test/resources/client_keys/valid.json
deleted file mode 100644
index a2d6a41..0000000
--- a/bukkit/src/test/resources/client_keys/valid.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "expires_at": "2022-06-12T10:46:26.421156927Z",
- "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU4I+xmDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWcPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
- "signature": "BYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
-}
diff --git a/bukkit/src/test/resources/client_keys/valid_public_key.json b/bukkit/src/test/resources/client_keys/valid_public_key.json
new file mode 100644
index 0000000..8943e87
--- /dev/null
+++ b/bukkit/src/test/resources/client_keys/valid_public_key.json
@@ -0,0 +1,5 @@
+{
+ "expires_at": "2022-06-20T08:31:47.318722344Z",
+ "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApd3ZxDhcRWWru1XEBke6uYqmbnS2Oxyk\nOMj+QDKrkwUqhVJYciyXGsMx46Mgr/KIoGCcokP5OtIxc6+69/ZLqJ9PvM81kLIxAqyvfBMKMGjP\n376LgxTF1FeDpbe5zXaNRxfmnvQhS5YTLbzgk36qWVjqxJMG4VLVmh7RV5zWsb7XlckZb2zRHM2Y\nMHbEC+ggX+l6zQyfG1KK0MH5k+O6b0xD0rv1wm24sLOesTXH6RZG8cNE3ofdnavxjFodTOnra6w1\naiVcoUTdEPSS86wQwq9j0YCcAKOwMXsqbk9NhpujrdyJ94dev+ELwkNS7P0pPrcfiyFTQeJCZTXz\nJB36MwIDAQAB\n-----END RSA PUBLIC KEY-----\n",
+ "signature": "lfRXK4zL213wBKg760eiPV7yvnLZ6a6v9Iohmw78yxIzqXO3tfrC5Z+P2LGiO1BdI4xckx8yz4ktn82zX97+r2zktBw0As7g71H/FjInpoZ76j3gMUaiFNrQJ0vKCCI7xsjonemroWAVDCAqlvdyqwUu/Fnz85+WoR2kCQ721vwy6IjWA3xhq8XrWjkI/AlBmoS/kVqnvjjjc9vocdddJXbUYzCse/hWWIbsFeBXyiGCd3v7apgtXwQfM++tt87fq7444zQskiYb14oQP8/uNwqZWQ9jAs00i1BZ0MNM6+TZYGHOfS6rbHZ1bcX34VZdcCwpapK/Z2HBRIgDN4QOcgJkyq1GcjvlM2wjfhN8gXTsmbF9Ee+5Y6a4ONRkxRZK2sT8oAXdm0OlTEGB0P0+WRRFOQ/PnRqbI7lvANao2METT2EUHHrtqFMe53kqCHdzy5qyuHxdCEa6l/gSR08fybx9DdRRmhOlhSPGxhgwqyi1fEMrN4CsSKNrv5u+sMqhspA05b3DQJeLDX+UV5ujRHwm0A49NF+h1ZYlrcefz5IMUUisOOw6HiLc/YGLD2jHwSePGdfMwMnrIxbxjCta7/7A91aaN7eYm16KW9erCOwAfJmBSQC6Pbmg5f7rd7rAKVOPxglq7nayXmd+BK53Mal5tltMSgd/0iY6SEtGSEU="
+}
diff --git a/bukkit/src/test/resources/signature/README.md b/bukkit/src/test/resources/signature/README.md
new file mode 100644
index 0000000..cc603bc
--- /dev/null
+++ b/bukkit/src/test/resources/signature/README.md
@@ -0,0 +1,16 @@
+# About
+
+This contains test resources for the unit tests. Files in this folder include pre-made cryptographic signatures.
+
+## Directory structure
+
+* `valid_signature.json`: Extracted using packet extract from actual authentication
+* `incorrect_nonce.json`: Different nonce token simulating that the server expected a different token than signed
+* `incorrect_salt.json`: Salt sent is different to the content signed by the signature (changed salt field)
+* `incorrect_signature.json`: Changed signature
+
+## File content
+
+* `nonce`: Server generated nonce token
+* `salt`: Client generated random token
+* `signature`: Nonce and salt signed using the client key from `valid_public_key.json`
diff --git a/bukkit/src/test/resources/signature/incorrect_nonce.json b/bukkit/src/test/resources/signature/incorrect_nonce.json
new file mode 100644
index 0000000..b88c0f5
--- /dev/null
+++ b/bukkit/src/test/resources/signature/incorrect_nonce.json
@@ -0,0 +1,7 @@
+{
+ "nonce": "galNig\u003d\u003d",
+ "signature": {
+ "signature": "JlXAUtIGDjxUOnF5vkg/NUEN2wlzXcqADyYIw2WRTb5hgKwIgxyUPO5v/2M7xU3hxz2Zf0iYHM97h8qNMGQ43cLgfVH9VWZ1kGMuOby2LNSb6nDaMzm0b02ftThaWOWj9kJXbR8fN7qdpB+28t2CTW5ILT+2AZYI/Sn8gFFR+LvJJt1ENMfEj2ZIIkHecpNBuKyLz1aDCZ5BEASSLfAqHEAA3dpHV1DIgzfpO6xwo7bVFDtcBEeusl/Nc3KyGyT8sDFTsZWgitgz53xNKrZUK8Q2BaJfP0zrGAX36rpYURJSVD0AtI1ic9s5aG+OFUC1YhLXb/1cDv37ZjHcdV2ppw\u003d\u003d",
+ "salt": -2985008842905108412
+ }
+}
diff --git a/bukkit/src/test/resources/signature/incorrect_salt.json b/bukkit/src/test/resources/signature/incorrect_salt.json
new file mode 100644
index 0000000..8edffb6
--- /dev/null
+++ b/bukkit/src/test/resources/signature/incorrect_salt.json
@@ -0,0 +1,7 @@
+{
+ "nonce": "GalNig\u003d\u003d",
+ "signature": {
+ "signature": "JlXAUtIGDjxUOnF5vkg/NUEN2wlzXcqADyYIw2WRTb5hgKwIgxyUPO5v/2M7xU3hxz2Zf0iYHM97h8qNMGQ43cLgfVH9VWZ1kGMuOby2LNSb6nDaMzm0b02ftThaWOWj9kJXbR8fN7qdpB+28t2CTW5ILT+2AZYI/Sn8gFFR+LvJJt1ENMfEj2ZIIkHecpNBuKyLz1aDCZ5BEASSLfAqHEAA3dpHV1DIgzfpO6xwo7bVFDtcBEeusl/Nc3KyGyT8sDFTsZWgitgz53xNKrZUK8Q2BaJfP0zrGAX36rpYURJSVD0AtI1ic9s5aG+OFUC1YhLXb/1cDv37ZjHcdV2ppw\u003d\u003d",
+ "salt": -1985008842905108412
+ }
+}
diff --git a/bukkit/src/test/resources/signature/incorrect_signature.json b/bukkit/src/test/resources/signature/incorrect_signature.json
new file mode 100644
index 0000000..ba6bac5
--- /dev/null
+++ b/bukkit/src/test/resources/signature/incorrect_signature.json
@@ -0,0 +1,7 @@
+{
+ "nonce": "GalNig\u003d\u003d",
+ "signature": {
+ "signature": "jlXAUtIGDjxUOnF5vkg/NUEN2wlzXcqADyYIw2WRTb5hgKwIgxyUPO5v/2M7xU3hxz2Zf0iYHM97h8qNMGQ43cLgfVH9VWZ1kGMuOby2LNSb6nDaMzm0b02ftThaWOWj9kJXbR8fN7qdpB+28t2CTW5ILT+2AZYI/Sn8gFFR+LvJJt1ENMfEj2ZIIkHecpNBuKyLz1aDCZ5BEASSLfAqHEAA3dpHV1DIgzfpO6xwo7bVFDtcBEeusl/Nc3KyGyT8sDFTsZWgitgz53xNKrZUK8Q2BaJfP0zrGAX36rpYURJSVD0AtI1ic9s5aG+OFUC1YhLXb/1cDv37ZjHcdV2ppw\u003d\u003d",
+ "salt": -2985008842905108412
+ }
+}
diff --git a/bukkit/src/test/resources/signature/valid_signature.json b/bukkit/src/test/resources/signature/valid_signature.json
new file mode 100644
index 0000000..7f4f4ad
--- /dev/null
+++ b/bukkit/src/test/resources/signature/valid_signature.json
@@ -0,0 +1,7 @@
+{
+ "nonce": "GalNig\u003d\u003d",
+ "signature": {
+ "signature": "JlXAUtIGDjxUOnF5vkg/NUEN2wlzXcqADyYIw2WRTb5hgKwIgxyUPO5v/2M7xU3hxz2Zf0iYHM97h8qNMGQ43cLgfVH9VWZ1kGMuOby2LNSb6nDaMzm0b02ftThaWOWj9kJXbR8fN7qdpB+28t2CTW5ILT+2AZYI/Sn8gFFR+LvJJt1ENMfEj2ZIIkHecpNBuKyLz1aDCZ5BEASSLfAqHEAA3dpHV1DIgzfpO6xwo7bVFDtcBEeusl/Nc3KyGyT8sDFTsZWgitgz53xNKrZUK8Q2BaJfP0zrGAX36rpYURJSVD0AtI1ic9s5aG+OFUC1YhLXb/1cDv37ZjHcdV2ppw\u003d\u003d",
+ "salt": -2985008842905108412
+ }
+}
|
||
|
|
bc7c4eea60 | Use PublicKey instead of byte representation | ||
|
|
456342c686 |
Migrate to ProtocolLib field extractors for better compatibility
diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index c4caae8..9b3c5c5 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -183,7 +183,7 @@
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
- <version>5.0.0-20220603.031413-2</version>
+ <version>5.0.0-SNAPSHOT</version>
<scope>provided</scope>
<exclusions>
<exclusion>
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 c9e72fc..3c66e7b 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
@@ -27,12 +27,12 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
-import com.comphenix.protocol.events.InternalStructure;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
-import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
+import com.comphenix.protocol.wrappers.WrappedProfilePublicKey;
+import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
@@ -47,7 +47,6 @@ import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.time.Instant;
-import java.util.Optional;
import org.bukkit.entity.Player;
@@ -171,15 +170,15 @@ public class ProtocolLibListener extends PacketAdapter {
}
private boolean verifyPublicKey(PacketContainer packet) {
- Optional<InternalStructure> internalStructure = packet.getOptionalStructures().readSafely(0);
- if (internalStructure == null) {
+ WrappedProfileKeyData profileKey = packet.getProfilePublicKeys().optionRead(0)
+ .map(WrappedProfilePublicKey::getKeyData).orElse(null);
+ if (profileKey == null) {
return true;
}
- Object instance = internalStructure.get().getHandle();
- Instant expires = FuzzyReflection.getFieldValue(instance, Instant.class, true);
- PublicKey key = FuzzyReflection.getFieldValue(instance, PublicKey.class, true);
- byte[] signature = FuzzyReflection.getFieldValue(instance, byte[].class, true);
+ Instant expires = profileKey.getExpireTime();
+ PublicKey key = profileKey.getKey();
+ byte[] signature = profileKey.getSignature();
ClientPublicKey clientKey = new ClientPublicKey(expires, key.getEncoded(), signature);
try {
return EncryptionUtil.verifyClientKey(clientKey, Instant.now());
|
||
|
|
e85d0d3f0e | Add session key to plugin | ||
|
|
d6c6108a7e | Do not modify certificate file during packaging phase | ||
|
|
d353ac66ab |
Verify public keys from players
diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index 2e1ccc4..c4caae8 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -119,9 +119,6 @@
<repository>
<id>dmulloy2-repo</id>
<url>https://repo.dmulloy2.net/repository/public/</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
</repository>
<!-- AuthMe Reloaded, xAuth and LoginSecurity -->
@@ -186,7 +183,7 @@
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
- <version>5.0.0-SNAPSHOT</version>
+ <version>5.0.0-20220603.031413-2</version>
<scope>provided</scope>
<exclusions>
<exclusion>
@@ -351,5 +348,12 @@
<scope>system</scope>
<systemPath>${project.basedir}/lib/UltraAuth v2.1.2.jar</systemPath>
</dependency>
+
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk18on</artifactId>
+ <version>1.71</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java
index 1197514..143dda9 100644
--- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtil.java
@@ -25,15 +25,28 @@
*/
package com.github.games647.fastlogin.bukkit.listener.protocollib;
+import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
+import com.google.common.io.Resources;
+
+import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.time.Instant;
+import java.util.Base64;
+import java.util.Base64.Encoder;
import java.util.Random;
import javax.crypto.Cipher;
@@ -46,11 +59,25 @@ import javax.crypto.spec.SecretKeySpec;
*
* @see net.minecraft.server.MinecraftEncryption
*/
-public class EncryptionUtil {
+class EncryptionUtil {
public static final int VERIFY_TOKEN_LENGTH = 4;
public static final String KEY_PAIR_ALGORITHM = "RSA";
+ private static final int RSA_LENGTH = 1_024;
+
+ private static final PublicKey mojangSessionKey;
+ private static final int LINE_LENGTH = 76;
+ private static final Encoder KEY_ENCODER = Base64.getMimeEncoder(LINE_LENGTH, "\n".getBytes(StandardCharsets.UTF_8));
+
+ static {
+ try {
+ mojangSessionKey = loadMojangSessionKey();
+ } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException ex) {
+ throw new RuntimeException("Failed to load Mojang session key", ex);
+ }
+ }
+
private EncryptionUtil() {
// utility
}
@@ -65,7 +92,7 @@ public class EncryptionUtil {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_ALGORITHM);
- keyPairGenerator.initialize(1_024);
+ keyPairGenerator.initialize(RSA_LENGTH);
return keyPairGenerator.generateKeyPair();
} catch (NoSuchAlgorithmException nosuchalgorithmexception) {
// Should be existing in every vm
@@ -120,6 +147,33 @@ public class EncryptionUtil {
return new SecretKeySpec(decrypt(privateKey, sharedKey), "AES");
}
+ public static boolean verifyClientKey(ClientPublicKey clientKey, Instant verifyTimstamp)
+ throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {
+ if (!verifyTimstamp.isBefore(clientKey.getExpiry())) {
+ return false;
+ }
+
+ Signature signature = Signature.getInstance("SHA1withRSA");
+ signature.initVerify(mojangSessionKey);
+ signature.update(toSignable(clientKey).getBytes(StandardCharsets.US_ASCII));
+ return signature.verify(clientKey.getSignature());
+ }
+
+ private static PublicKey loadMojangSessionKey()
+ throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
+ var keyUrl = Resources.getResource("yggdrasil_session_pubkey.der");
+ var keyData = Resources.toByteArray(keyUrl);
+ var keySpec = new X509EncodedKeySpec(keyData);
+
+ return KeyFactory.getInstance("RSA").generatePublic(keySpec);
+ }
+
+ private static String toSignable(ClientPublicKey clientPublicKey) {
+ long expiry = clientPublicKey.getExpiry().toEpochMilli();
+ String encoded = KEY_ENCODER.encodeToString(clientPublicKey.getKey());
+ return expiry + "-----BEGIN RSA PUBLIC KEY-----\n" + encoded + "\n-----END RSA PUBLIC KEY-----\n";
+ }
+
public static byte[] decrypt(PrivateKey key, byte[] data) throws GeneralSecurityException {
// b(Key var0, byte[] var1)
Cipher cipher = Cipher.getInstance(key.getAlgorithm());
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 f8b8de2..c9e72fc 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
@@ -27,18 +27,27 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
+import com.comphenix.protocol.events.InternalStructure;
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.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
+import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
+import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
import com.github.games647.fastlogin.core.antibot.AntiBotService;
import com.github.games647.fastlogin.core.antibot.AntiBotService.Action;
import java.net.InetSocketAddress;
+import java.security.InvalidKeyException;
import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.time.Instant;
+import java.util.Optional;
import org.bukkit.entity.Player;
@@ -149,6 +158,11 @@ public class ProtocolLibListener extends PacketAdapter {
username = (String) packetEvent.getPacket().getMeta("original_name").get();
}
+ if (!verifyPublicKey(packet)) {
+ plugin.getLog().warn("Invalid public key from player {}", username);
+ return;
+ }
+
plugin.getLog().trace("GameProfile {} with {} connecting", sessionKey, username);
packetEvent.getAsyncMarker().incrementProcessingDelay();
@@ -156,6 +170,24 @@ public class ProtocolLibListener extends PacketAdapter {
plugin.getScheduler().runAsync(nameCheckTask);
}
+ private boolean verifyPublicKey(PacketContainer packet) {
+ Optional<InternalStructure> internalStructure = packet.getOptionalStructures().readSafely(0);
+ if (internalStructure == null) {
+ return true;
+ }
+
+ Object instance = internalStructure.get().getHandle();
+ Instant expires = FuzzyReflection.getFieldValue(instance, Instant.class, true);
+ PublicKey key = FuzzyReflection.getFieldValue(instance, PublicKey.class, true);
+ byte[] signature = FuzzyReflection.getFieldValue(instance, byte[].class, true);
+ ClientPublicKey clientKey = new ClientPublicKey(expires, key.getEncoded(), signature);
+ try {
+ return EncryptionUtil.verifyClientKey(clientKey, Instant.now());
+ } catch (SignatureException | InvalidKeyException | NoSuchAlgorithmException ex) {
+ return false;
+ }
+ }
+
private String getUsername(PacketContainer packet) {
WrappedGameProfile profile = packet.getGameProfiles().readSafely(0);
if (profile == null) {
diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/packet/ClientPublicKey.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/packet/ClientPublicKey.java
new file mode 100644
index 0000000..495adb1
--- /dev/null
+++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/packet/ClientPublicKey.java
@@ -0,0 +1,53 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2022 games647 and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.github.games647.fastlogin.bukkit.listener.protocollib.packet;
+
+import java.time.Instant;
+
+public class ClientPublicKey {
+
+ private final Instant expiry;
+ private final byte[] key;
+ private final byte[] signature;
+
+ public ClientPublicKey(Instant expiry, byte[] key, byte[] signature) {
+ this.expiry = expiry;
+ this.key = key;
+ this.signature = signature;
+ }
+
+ public Instant getExpiry() {
+ return expiry;
+ }
+
+ public byte[] getKey() {
+ return key;
+ }
+
+ public byte[] getSignature() {
+ return signature;
+ }
+}
diff --git a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java
index 7a097f1..11a52f7 100644
--- a/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java
+++ b/bukkit/src/test/java/com/github/games647/fastlogin/bukkit/listener/protocollib/EncryptionUtilTest.java
@@ -25,8 +25,27 @@
*/
package com.github.games647.fastlogin.bukkit.listener.protocollib;
+import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
+import com.google.common.io.Resources;
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Base64;
+import org.bouncycastle.util.io.pem.PemObject;
+import org.bouncycastle.util.io.pem.PemReader;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
@@ -43,4 +62,77 @@ public class EncryptionUtilTest {
assertThat(token, notNullValue());
assertThat(token.length, is(4));
}
+
+ @Test
+ public void testExpiredClientKey() throws Exception {
+ var clientKey = loadClientKey("client_keys/valid.json");
+
+ // Client expires at the exact second mentioned, so use it for verification
+ var expiredTimestamp = clientKey.getExpiry();
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, expiredTimestamp), is(false));
+ }
+
+ // @Test(expected = Exception.class)
+ @Test
+ public void testInvalidChangedExpiration() throws Exception {
+ // expiration date changed should make the signature invalid
+ // expiration should still be valid
+ var clientKey = loadClientKey("client_keys/invalid_wrong_expiration.json");
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, clientKey.getExpiry().minus(5, ChronoUnit.HOURS)), is(false));
+ }
+
+ // @Test(expected = Exception.class)
+ @Test
+ public void testInvalidChangedKey() throws Exception {
+ // changed public key no longer corresponding to the signature
+ var clientKey = loadClientKey("client_keys/invalid_wrong_key.json");
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, clientKey.getExpiry().minus(5, ChronoUnit.HOURS)), is(false));
+ }
+
+ @Test
+ public void testInvalidChangedSignature() throws Exception {
+ // signature modified no longer corresponding to key and expiration date
+ var clientKey = loadClientKey("client_keys/invalid_wrong_signature.json");
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, clientKey.getExpiry().minus(5, ChronoUnit.HOURS)), is(false));
+ }
+
+ @Test
+ public void testValidClientKey() throws Exception {
+ var clientKey = loadClientKey("client_keys/valid.json");
+
+ var verificationTimestamp = clientKey.getExpiry().minus(5, ChronoUnit.HOURS);
+ assertThat(EncryptionUtil.verifyClientKey(clientKey, verificationTimestamp), is(true));
+ }
+
+ private ClientPublicKey loadClientKey(String path)
+ throws NoSuchAlgorithmException, IOException, InvalidKeySpecException {
+ var keyUrl = Resources.getResource(path);
+ var gson = new Gson();
+
+ var lines = Resources.toString(keyUrl, StandardCharsets.US_ASCII);
+ var object = gson.fromJson(lines, JsonObject.class);
+
+ Instant expires = Instant.parse(object.getAsJsonPrimitive("expires_at").getAsString());
+ String key = object.getAsJsonPrimitive("key").getAsString();
+ RSAPublicKey publicKey = parsePublicKey(key);
+
+ byte[] signature = Base64.getDecoder().decode(object.getAsJsonPrimitive("signature").getAsString());
+ return new ClientPublicKey(expires, publicKey.getEncoded(), signature);
+ }
+
+ private RSAPublicKey parsePublicKey(String lines)
+ throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
+ try (
+ Reader reader = new StringReader(lines);
+ PemReader pemReader = new PemReader(reader)
+ ) {
+
+ PemObject pemObject = pemReader.readPemObject();
+ byte[] content = pemObject.getContent();
+ var pubKeySpec = new X509EncodedKeySpec(content);
+
+ var factory = KeyFactory.getInstance("RSA");
+ return (RSAPublicKey) factory.generatePublic(pubKeySpec);
+ }
+ }
}
diff --git a/bukkit/src/test/resources/client_keys/invalid_wrong_expiration.json b/bukkit/src/test/resources/client_keys/invalid_wrong_expiration.json
new file mode 100644
index 0000000..7ecc12e
--- /dev/null
+++ b/bukkit/src/test/resources/client_keys/invalid_wrong_expiration.json
@@ -0,0 +1,5 @@
+{
+ "expires_at": "2022-06-12T09:46:26.421156927Z",
+ "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU4I+xm\nDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/\n33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZ\nOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF\n4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWc\nPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
+ "signature": "BYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
+}
diff --git a/bukkit/src/test/resources/client_keys/invalid_wrong_key.json b/bukkit/src/test/resources/client_keys/invalid_wrong_key.json
new file mode 100644
index 0000000..37bb3ad
--- /dev/null
+++ b/bukkit/src/test/resources/client_keys/invalid_wrong_key.json
@@ -0,0 +1,5 @@
+{
+ "expires_at": "2022-06-12T10:46:26.421156927Z",
+ "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU3I+xmDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWcPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
+ "signature": "BYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
+}
diff --git a/bukkit/src/test/resources/client_keys/invalid_wrong_signature.json b/bukkit/src/test/resources/client_keys/invalid_wrong_signature.json
new file mode 100644
index 0000000..cbca4b1
--- /dev/null
+++ b/bukkit/src/test/resources/client_keys/invalid_wrong_signature.json
@@ -0,0 +1,5 @@
+{
+ "expires_at": "2022-06-12T10:46:26.421156927Z",
+ "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU4I+xm\nDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/\n33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZ\nOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF\n4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWc\nPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
+ "signature": "bYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
+}
diff --git a/bukkit/src/test/resources/client_keys/valid.json b/bukkit/src/test/resources/client_keys/valid.json
new file mode 100644
index 0000000..a2d6a41
--- /dev/null
+++ b/bukkit/src/test/resources/client_keys/valid.json
@@ -0,0 +1,5 @@
+{
+ "expires_at": "2022-06-12T10:46:26.421156927Z",
+ "key": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoOv23jt2QPyab6bPRBwH2ggmzQU4I+xmDpi3X5ZB5Em/4uzyZqNVLJc0gShpk0XsdoB28Nq1bPxczOTBxuXi3rg5ax5gL+iymDSU27DLM8s/33lOofzGPJUEQGKlFm0QelDKZ/q5Y/9inHE3hEJKf7h0tnmGahXFmZSF/nRz9GHnfSYpjtDr9bsZOzQuLhHXT5E4ksNRTFW41h0MlZ1qOhO+NiiVgk7LmgVYiV7RRbgO8U6RaCEqg5n28Ewo6QtzB+DF4NTDeu3E9BLH5G0npdUrVNhdRUWCFDmH6n9hqSIz2J7o6GvWqEvp0h9e/3qtLsoS60hnQXunrcWcPaEIYQIDAQAB\n-----END RSA PUBLIC KEY-----\n",
+ "signature": "BYv2mKJvz5O3Wo5V5sbJI0L6zAjfzQSkTNd7ykd/MB7KPPDg4zoTuOqphmh042xz1EYbMcfqEZvP04NTaoZDx+IxGieBB+LuxqnmYKIgtpcR2SEpzbSKznSHkupr1hKwF7kCVWLlwSbxc/XRlWPPyT6FE9m628A/jFb/obgfzLLQWfTFWp6kq2oBoUUQV5om2ihdrJ8oLCsw10SGdcFtK4+UuLzz+wjwv3JpvIX93IKdjFnw0KNd110HOPWZgp2n8+f6GsecysorqvwaE1rJC0m9Qa/wFsK2TY7twSMreCrbXPaBiWrkRovtm9gnaBwD+iuZYlnLvO0ld8qW928LL2vFBTi3TsPUWC3i/xYnAR2m8YP2hiCLHuPfSJmgfxHsM2iRdrR8qdOUkiC9h34STEA7Q2+rWkNWJ+YKYVTIkyqHEuXqU87txhVTaRJi6UDGDn49cMKmZwQnn+23JQf1chcn1YFkrivDaJPhm17GhoEldQHSLQfxb0ifja5WBNDbkKBF/h9JqvG3Ya9anxlyxY6g7/m2zP73xfkvUnejoX4GKjffEqezQmTe9RIeuWyz94nfZNLr0Ps363kAfP4KSW+f4zkTU/UVg19ccAY0ZhiwDetKyksU5WqLO8xMPZ6PNFYhNeBb2yhGdT8PidkRYkC4XBn1k7F7apiNUuZU8aA="
+}
|
||
|
|
4fa28f2c69 |
Support username extraction in 1.19
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 d1f83a6..f8b8de2 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
@@ -31,6 +31,7 @@ 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.comphenix.protocol.wrappers.WrappedGameProfile;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.antibot.AntiBotService;
import com.github.games647.fastlogin.core.antibot.AntiBotService.Action;
@@ -94,7 +95,7 @@ public class ProtocolLibListener extends PacketAdapter {
PacketContainer packet = packetEvent.getPacket();
InetSocketAddress address = sender.getAddress();
- String username = packet.getGameProfiles().read(0).getName();
+ String username = getUsername(packet);
Action action = antiBotService.onIncomingConnection(address, username);
switch (action) {
@@ -154,4 +155,14 @@ public class ProtocolLibListener extends PacketAdapter {
Runnable nameCheckTask = new NameCheckTask(plugin, random, player, packetEvent, username, keyPair.getPublic());
plugin.getScheduler().runAsync(nameCheckTask);
}
+
+ private String getUsername(PacketContainer packet) {
+ WrappedGameProfile profile = packet.getGameProfiles().readSafely(0);
+ if (profile == null) {
+ return packet.getStrings().read(0);
+ }
+
+ //player.getName() won't work at this state
+ return profile.getName();
+ }
}
|
||
|
|
d8a6e2a6fa |
Update ProtocolLib to 5.0
diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index 13e466e..2494a2b 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -186,7 +186,7 @@
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
- <version>4.8.0</version>
+ <version>5.0.0-SNAPSHOT</version>
<scope>provided</scope>
<exclusions>
<exclusion>
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 5a2794d..2e60cd1 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
@@ -28,7 +28,7 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
-import com.comphenix.protocol.injector.server.TemporaryPlayerFactory;
+import com.comphenix.protocol.injector.temporary.TemporaryPlayerFactory;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.utility.MinecraftReflection;
@@ -37,18 +37,14 @@ import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.github.games647.craftapi.model.auth.Verification;
import com.github.games647.craftapi.model.skin.SkinProperty;
-import com.github.games647.craftapi.resolver.AbstractResolver;
import com.github.games647.craftapi.resolver.MojangResolver;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.Reader;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.net.*;
-import java.nio.charset.StandardCharsets;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyPair;
@@ -263,15 +259,11 @@ public class VerifyResponseTask implements Runnable {
private void kickPlayer(String reason) {
PacketContainer kickPacket = new PacketContainer(DISCONNECT);
kickPacket.getChatComponents().write(0, WrappedChatComponent.fromText(reason));
- try {
- //send kick packet at login state
- //the normal event.getPlayer.kickPlayer(String) method does only work at play state
- ProtocolLibrary.getProtocolManager().sendServerPacket(player, kickPacket);
- //tell the server that we want to close the connection
- player.kickPlayer("Disconnect");
- } catch (InvocationTargetException ex) {
- plugin.getLog().error("Error sending kick packet for: {}", player, ex);
- }
+ //send kick packet at login state
+ //the normal event.getPlayer.kickPlayer(String) method does only work at play state
+ ProtocolLibrary.getProtocolManager().sendServerPacket(player, kickPacket);
+ //tell the server that we want to close the connection
+ player.kickPlayer("Disconnect");
}
//fake a new login packet in order to let the server handle all the other stuff
@@ -287,14 +279,8 @@ public class VerifyResponseTask implements Runnable {
startPacket.getGameProfiles().write(0, fakeProfile);
}
- try {
- //we don't want to handle our own packets so ignore filters
- startPacket.setMeta(ProtocolLibListener.SOURCE_META_KEY, plugin.getName());
- ProtocolLibrary.getProtocolManager().recieveClientPacket(player, startPacket, true);
- } catch (InvocationTargetException | IllegalAccessException ex) {
- plugin.getLog().warn("Failed to fake a new start packet for: {}", username, ex);
- //cancel the event in order to prevent the server receiving an invalid packet
- kickPlayer(plugin.getCore().getMessage("error-kick"));
- }
+ //we don't want to handle our own packets so ignore filters
+ startPacket.setMeta(ProtocolLibListener.SOURCE_META_KEY, plugin.getName());
+ ProtocolLibrary.getProtocolManager().receiveClientPacket(player, startPacket, true);
}
}
|
||
|
|
219ebb1248 | Bump version | ||
|
|
87281be8cf | Fix start packet containing username in 1.19 | ||
|
|
e781eb6c68 |
Revert "Add support for checking velocity support with newer paper configs"
This reverts commit
|
||
|
|
9ba6e9ba90 | Add missing license header | ||
|
|
f182adc3bc |
Add support for RGB colors using the color char
Examples include: `&x00002a00002b&lText` |
||
|
|
5e159cac64 |
Explicitly disable ProtocolLib listener on stop
This will stop Paper complaining about still running asynchronous tasks which is a useful feature. |
||
|
|
6f9e8a49f1 |
Add support for checking velocity support with newer paper configs
Fixes #802 |
||
|
|
57b7fe949f |
Merge pull request #823 from games647/805-more-antibot-features
Add support for blocking incoming connection on AntiBot detection |
||
|
|
32fe2cdf4e |
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. |
||
|
|
7cab5993b7 |
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<Comman
}
if (pluginManager.isPluginEnabled("ProtocolSupport")) {
- pluginManager.registerEvents(new ProtocolSupportListener(this, core.getRateLimiter()), this);
+ pluginManager.registerEvents(new ProtocolSupportListener(this, core.getAntiBot()), this);
} else if (pluginManager.isPluginEnabled("ProtocolLib")) {
- ProtocolLibListener.register(this, core.getRateLimiter());
+ ProtocolLibListener.register(this, core.getAntiBot());
if (isPluginInstalled("floodgate")) {
if (getConfig().getBoolean("floodgatePrefixWorkaround")){
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 8b3d601..3c161b7 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
@@ -31,8 +31,10 @@ 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.RateLimiter;
+import com.github.games647.fastlogin.core.antibot.AntiBotService;
+import com.github.games647.fastlogin.core.antibot.AntiBotService.Action;
+import java.net.InetSocketAddress;
import java.security.KeyPair;
import java.security.SecureRandom;
@@ -50,9 +52,9 @@ public class ProtocolLibListener extends PacketAdapter {
//just create a new once on plugin enable. This used for verify token generation
private final SecureRandom random = new SecureRandom();
private final KeyPair keyPair = EncryptionUtil.generateKeyPair();
- private final RateLimiter rateLimiter;
+ private final AntiBotService antiBotService;
- public ProtocolLibListener(FastLoginBukkit plugin, RateLimiter rateLimiter) {
+ public ProtocolLibListener(FastLoginBukkit plugin, AntiBotService antiBotService) {
//run async in order to not block the server, because we are making api calls to Mojang
super(params()
.plugin(plugin)
@@ -60,15 +62,15 @@ public class ProtocolLibListener extends PacketAdapter {
.optionAsync());
this.plugin = plugin;
- this.rateLimiter = rateLimiter;
+ this.antiBotService = antiBotService;
}
- public static void register(FastLoginBukkit plugin, RateLimiter rateLimiter) {
+ public static void register(FastLoginBukkit plugin, AntiBotService antiBotService) {
// they will be created with a static builder, because otherwise it will throw a NoClassDefFoundError
// TODO: make synchronous processing, but do web or database requests async
ProtocolLibrary.getProtocolManager()
.getAsynchronousManager()
- .registerAsyncHandler(new ProtocolLibListener(plugin, rateLimiter))
+ .registerAsyncHandler(new ProtocolLibListener(plugin, antiBotService))
.start();
}
@@ -88,12 +90,26 @@ public class ProtocolLibListener extends PacketAdapter {
Player sender = packetEvent.getPlayer();
PacketType packetType = packetEvent.getPacketType();
if (packetType == START) {
- if (!rateLimiter.tryAcquire()) {
- plugin.getLog().warn("Simple Anti-Bot join limit - Ignoring {}", sender);
- return;
+ PacketContainer packet = packetEvent.getPacket();
+
+ InetSocketAddress address = sender.getAddress();
+ String username = packet.getGameProfiles().read(0).getName();
+
+ Action action = antiBotService.onIncomingConnection(address, username);
+ switch (action) {
+ case Ignore:
+ // just ignore
+ return;
+ case Block:
+ String message = plugin.getCore().getMessage("kick-antibot");
+ sender.kickPlayer(message);
+ break;
+ case Continue:
+ default:
+ //player.getName() won't work at this state
+ onLogin(packetEvent, sender, username);
+ break;
}
-
- onLogin(packetEvent, sender);
} else {
onEncryptionBegin(packetEvent, sender);
}
@@ -113,18 +129,13 @@ public class ProtocolLibListener extends PacketAdapter {
plugin.getScheduler().runAsync(verifyTask);
}
- private void onLogin(PacketEvent packetEvent, Player player) {
+ private void onLogin(PacketEvent packetEvent, Player player, String username) {
//this includes ip:port. Should be unique for an incoming login request with a timeout of 2 minutes
String sessionKey = player.getAddress().toString();
//remove old data every time on a new login in order to keep the session only for one person
plugin.removeSession(player.getAddress());
- //player.getName() won't work at this state
- PacketContainer packet = packetEvent.getPacket();
-
- String username = packet.getGameProfiles().read(0).getName();
-
if (packetEvent.getPacket().getMeta("original_name").isPresent()) {
//username has been injected by ManualNameChange.java
username = (String) packetEvent.getPacket().getMeta("original_name").get();
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 608078c..ce84824 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
@@ -29,8 +29,9 @@ import com.github.games647.craftapi.UUIDAdapter;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPreLoginEvent;
-import com.github.games647.fastlogin.core.RateLimiter;
import com.github.games647.fastlogin.core.StoredProfile;
+import com.github.games647.fastlogin.core.antibot.AntiBotService;
+import com.github.games647.fastlogin.core.antibot.AntiBotService.Action;
import com.github.games647.fastlogin.core.shared.JoinManagement;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
@@ -49,13 +50,13 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
implements Listener {
private final FastLoginBukkit plugin;
- private final RateLimiter rateLimiter;
+ private final AntiBotService antiBotService;
- public ProtocolSupportListener(FastLoginBukkit plugin, RateLimiter rateLimiter) {
+ public ProtocolSupportListener(FastLoginBukkit plugin, AntiBotService antiBotService) {
super(plugin.getCore(), plugin.getCore().getAuthPluginHook(), plugin.getBedrockService());
this.plugin = plugin;
- this.rateLimiter = rateLimiter;
+ this.antiBotService = antiBotService;
}
@EventHandler
@@ -64,19 +65,28 @@ public class ProtocolSupportListener extends JoinManagement<Player, CommandSende
return;
}
- if (!rateLimiter.tryAcquire()) {
- plugin.getLog().warn("Simple Anti-Bot join limit - Ignoring {}", loginStartEvent.getConnection());
- return;
- }
-
String username = loginStartEvent.getConnection().getProfile().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.removeSession(address);
-
- ProtocolLoginSource source = new ProtocolLoginSource(loginStartEvent);
- super.onLogin(username, source);
+ 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");
+ loginStartEvent.denyLogin(message);
+ break;
+ case Continue:
+ default:
+ //remove old data every time on a new login in order to keep the session only for one person
+ plugin.removeSession(address);
+
+ ProtocolLoginSource source = new ProtocolLoginSource(loginStartEvent);
+ super.onLogin(username, source);
+ break;
+ }
}
@EventHandler
diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/ConnectListener.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/ConnectListener.java
index a8c894d..ddd7e97 100644
--- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/ConnectListener.java
+++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/ConnectListener.java
@@ -32,7 +32,8 @@ import com.github.games647.fastlogin.bungee.task.AsyncPremiumCheck;
import com.github.games647.fastlogin.bungee.task.FloodgateAuthTask;
import com.github.games647.fastlogin.bungee.task.ForceLoginTask;
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.hooks.bedrock.FloodgateService;
import com.github.games647.fastlogin.core.shared.LoginSession;
import com.google.common.base.Throwables;
@@ -41,8 +42,10 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Field;
+import java.net.InetSocketAddress;
import java.util.UUID;
+import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.Server;
@@ -92,12 +95,12 @@ public class ConnectListener implements Listener {
}
private final FastLoginBungee plugin;
- private final RateLimiter rateLimiter;
+ private final AntiBotService antiBotService;
private final Property[] emptyProperties = {};
- public ConnectListener(FastLoginBungee plugin, RateLimiter rateLimiter) {
+ public ConnectListener(FastLoginBungee plugin, AntiBotService antiBotService) {
this.plugin = plugin;
- this.rateLimiter = rateLimiter;
+ this.antiBotService = antiBotService;
}
@EventHandler
@@ -107,17 +110,28 @@ public class ConnectListener implements Listener {
return;
}
- if (!rateLimiter.tryAcquire()) {
- plugin.getLog().warn("Simple Anti-Bot join limit - Ignoring {}", connection);
- return;
- }
-
+ InetSocketAddress address = preLoginEvent.getConnection().getAddress();
String username = connection.getName();
+
plugin.getLog().info("Incoming login request for {} from {}", username, connection.getSocketAddress());
- preLoginEvent.registerIntent(plugin);
- Runnable asyncPremiumCheck = new AsyncPremiumCheck(plugin, preLoginEvent, connection, username);
- 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");
+ preLoginEvent.setCancelReason(TextComponent.fromLegacyText(message));
+ preLoginEvent.setCancelled(true);
+ break;
+ case Continue:
+ default:
+ preLoginEvent.registerIntent(plugin);
+ Runnable asyncPremiumCheck = new AsyncPremiumCheck(plugin, preLoginEvent, connection, username);
+ plugin.getScheduler().runAsync(asyncPremiumCheck);
+ break;
+ }
}
@EventHandler(priority = EventPriority.LOWEST)
@@ -140,7 +154,7 @@ public class ConnectListener implements Listener {
StoredProfile playerProfile = session.getProfile();
playerProfile.setId(verifiedUUID);
- // bungeecord will do this automatically so override it on disabled option
+ // BungeeCord will do this automatically so override it on disabled option
if (uniqueIdSetter != null) {
InitialHandler initialHandler = (InitialHandler) connection;
diff --git a/core/src/main/java/com/github/games647/fastlogin/core/mojang/MojangApiConnector.java b/core/src/main/java/com/github/games647/fastlogin/core/antibot/AntiBotService.java
similarity index 57%
rename from core/src/main/java/com/github/games647/fastlogin/core/mojang/MojangApiConnector.java
rename to core/src/main/java/com/github/games647/fastlogin/core/antibot/AntiBotService.java
index 4321d6f..2848335 100644
--- a/core/src/main/java/com/github/games647/fastlogin/core/mojang/MojangApiConnector.java
+++ b/core/src/main/java/com/github/games647/fastlogin/core/antibot/AntiBotService.java
@@ -23,3 +23,40 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+package com.github.games647.fastlogin.core.antibot;
+
+import java.net.InetSocketAddress;
+
+import org.slf4j.Logger;
+
+public class AntiBotService {
+
+ private final Logger logger;
+
+ private final RateLimiter rateLimiter;
+ private final Action limitReachedAction;
+
+ public AntiBotService(Logger logger, RateLimiter rateLimiter, Action limitReachedAction) {
+ this.logger = logger;
+
+ this.rateLimiter = rateLimiter;
+ this.limitReachedAction = limitReachedAction;
+ }
+
+ public Action onIncomingConnection(InetSocketAddress clientAddress, String username) {
+ if (!rateLimiter.tryAcquire()) {
+ logger.warn("Anti-Bot join limit - Ignoring {}", clientAddress);
+ return limitReachedAction;
+ }
+
+ return Action.Continue;
+ }
+
+ public enum Action {
+ Ignore,
+
+ Block,
+
+ Continue;
+ }
+}
diff --git a/core/src/main/java/com/github/games647/fastlogin/core/mojang/ProxyAgnosticMojangResolver.java b/core/src/main/java/com/github/games647/fastlogin/core/antibot/ProxyAgnosticMojangResolver.java
similarity index 100%
rename from core/src/main/java/com/github/games647/fastlogin/core/mojang/ProxyAgnosticMojangResolver.java
rename to core/src/main/java/com/github/games647/fastlogin/core/antibot/ProxyAgnosticMojangResolver.java
diff --git a/core/src/main/java/com/github/games647/fastlogin/core/RateLimiter.java b/core/src/main/java/com/github/games647/fastlogin/core/antibot/RateLimiter.java
similarity index 96%
rename from core/src/main/java/com/github/games647/fastlogin/core/RateLimiter.java
rename to core/src/main/java/com/github/games647/fastlogin/core/antibot/RateLimiter.java
index 3ec2f75..b791ca5 100644
--- a/core/src/main/java/com/github/games647/fastlogin/core/RateLimiter.java
+++ b/core/src/main/java/com/github/games647/fastlogin/core/antibot/RateLimiter.java
@@ -23,7 +23,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-package com.github.games647.fastlogin.core;
+package com.github.games647.fastlogin.core.antibot;
@FunctionalInterface
public interface RateLimiter {
diff --git a/core/src/main/java/com/github/games647/fastlogin/core/TickingRateLimiter.java b/core/src/main/java/com/github/games647/fastlogin/core/antibot/TickingRateLimiter.java
similarity index 98%
rename from core/src/main/java/com/github/games647/fastlogin/core/TickingRateLimiter.java
rename to core/src/main/java/com/github/games647/fastlogin/core/antibot/TickingRateLimiter.java
index 6064229..ced7da1 100644
--- a/core/src/main/java/com/github/games647/fastlogin/core/TickingRateLimiter.java
+++ b/core/src/main/java/com/github/games647/fastlogin/core/antibot/TickingRateLimiter.java
@@ -23,7 +23,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-package com.github.games647.fastlogin.core;
+package com.github.games647.fastlogin.core.antibot;
import com.google.common.base.Ticker;
diff --git a/core/src/main/java/com/github/games647/fastlogin/core/mojang/UUIDTypeAdapter.java b/core/src/main/java/com/github/games647/fastlogin/core/mojang/UUIDTypeAdapter.java
deleted file mode 100644
index 4321d6f..0000000
--- a/core/src/main/java/com/github/games647/fastlogin/core/mojang/UUIDTypeAdapter.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SPDX-License-Identifier: MIT
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2015-2022 games647 and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
diff --git a/core/src/main/java/com/github/games647/fastlogin/core/shared/FastLoginCore.java b/core/src/main/java/com/github/games647/fastlogin/core/shared/FastLoginCore.java
index 9e2a49a..474a8e2 100644
--- a/core/src/main/java/com/github/games647/fastlogin/core/shared/FastLoginCore.java
+++ b/core/src/main/java/com/github/games647/fastlogin/core/shared/FastLoginCore.java
@@ -28,8 +28,10 @@ package com.github.games647.fastlogin.core.shared;
import com.github.games647.craftapi.resolver.MojangResolver;
import com.github.games647.craftapi.resolver.http.RotatingProxySelector;
import com.github.games647.fastlogin.core.CommonUtil;
-import com.github.games647.fastlogin.core.RateLimiter;
-import com.github.games647.fastlogin.core.TickingRateLimiter;
+import com.github.games647.fastlogin.core.antibot.AntiBotService;
+import com.github.games647.fastlogin.core.antibot.AntiBotService.Action;
+import com.github.games647.fastlogin.core.antibot.RateLimiter;
+import com.github.games647.fastlogin.core.antibot.TickingRateLimiter;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.hooks.DefaultPasswordGenerator;
import com.github.games647.fastlogin.core.hooks.PasswordGenerator;
@@ -88,7 +90,7 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
private Configuration config;
private SQLStorage storage;
- private RateLimiter rateLimiter;
+ private AntiBotService antiBot;
private PasswordGenerator<P> passwordGenerator = new DefaultPasswordGenerator<>();
private AuthPlugin<P> authPlugin;
@@ -122,7 +124,7 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
// 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<Proxy> proxies = config.getStringList("proxies")
.stream()
.map(HostAndPort::fromString)
@@ -144,20 +146,34 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
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<P extends C, C, T extends PlatformPlugin<C>> {
return authPlugin;
}
- public RateLimiter getRateLimiter() {
- return rateLimiter;
+ public AntiBotService getAntiBot() {
+ return antiBot;
}
public void setAuthPluginHook(AuthPlugin<P> 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
|
||
|
|
10785b32ac | Fix anti bot reading the correct values | ||
|
|
ae8c040d3e |
Merge pull request #814 from games647/dependabot/maven/org.geysermc.floodgate-api-2.2.0-SNAPSHOT
Bump api from 2.0-SNAPSHOT to 2.2.0-SNAPSHOT |
||
|
|
b221a3f294 |
Merge pull request #822 from games647/dependabot/github_actions/actions/cache-3.0.4
Bump actions/cache from 3.0.1 to 3.0.4 |
||
|
|
fb32f0b386 | Bump requried Java version to 17 | ||
|
|
752cb1c3a7 |
Bump actions/cache from 3.0.1 to 3.0.4
Bumps [actions/cache](https://github.com/actions/cache) from 3.0.1 to 3.0.4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.0.1...v3.0.4) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
f5ead50441 | Fix typo in pull request template | ||
|
|
b878ec34c8 | Fix Java workflow setup | ||
|
|
3d72e77345 | Fix Java version name | ||
|
|
18bd778b7e | General minor code clean up and typo fixes | ||
|
|
a9e4c90970 |
Merge pull request #799 from games647/dependabot/maven/org.mariadb.jdbc-mariadb-java-client-3.0.5
Bump mariadb-java-client from 3.0.4 to 3.0.51.11 |
||
|
|
c92f94d2e8 |
Bump api from 2.0-SNAPSHOT to 2.2.0-SNAPSHOT
Bumps api from 2.0-SNAPSHOT to 2.2.0-SNAPSHOT. --- updated-dependencies: - dependency-name: org.geysermc.floodgate:api dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
0af22d9927 |
Merge pull request #811 from Enginecrafter77/main
Support for transparent proxies / DNAT |
||
|
|
5abd864fa5 | fix: Typo in config.yml comment about useProxyAgnosticResolver |