mirror of
https://github.com/TuxCoding/FastLogin.git
synced 2025-07-30 02:37:34 +02:00
Generate a public key only for ProtocolLib listener
This commit is contained in:
14
README.md
14
README.md
@ -26,15 +26,15 @@ So they don't need to enter passwords. This is also called auto login (auto-logi
|
|||||||
***
|
***
|
||||||
|
|
||||||
### Commands:
|
### Commands:
|
||||||
* /premium [player] Label the invoker or the argument as paid account
|
/premium [player] Label the invoker or the argument as paid account
|
||||||
* /cracked [player] Label the invoker or the argument as cracked account
|
/cracked [player] Label the invoker or the argument as cracked account
|
||||||
|
|
||||||
### Permissions:
|
### Permissions:
|
||||||
* fastlogin.bukkit.command.premium
|
fastlogin.bukkit.command.premium
|
||||||
* fastlogin.bukkit.command.cracked
|
fastlogin.bukkit.command.cracked
|
||||||
* fastlogin.command.premium.other
|
fastlogin.command.premium.other
|
||||||
* fastlogin.command.cracked.other
|
fastlogin.command.cracked.other
|
||||||
* fastlogin.command.import
|
fastlogin.command.import
|
||||||
|
|
||||||
### Requirements:
|
### Requirements:
|
||||||
* Plugin: [ProtocolLib](https://www.spigotmc.org/resources/protocollib.1997/) or
|
* Plugin: [ProtocolLib](https://www.spigotmc.org/resources/protocollib.1997/) or
|
||||||
|
@ -127,7 +127,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>me.clip</groupId>
|
<groupId>me.clip</groupId>
|
||||||
<artifactId>placeholderapi</artifactId>
|
<artifactId>placeholderapi</artifactId>
|
||||||
<version>2.8.2</version>
|
<version>2.8.4</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
|
@ -40,19 +40,6 @@ public class BukkitLoginSession extends LoginSession {
|
|||||||
this(username, "", ArrayUtils.EMPTY_BYTE_ARRAY, false, profile);
|
this(username, "", ArrayUtils.EMPTY_BYTE_ARRAY, false, profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the random generated server id. This makes sure the request sent from the client is just for this server.
|
|
||||||
*
|
|
||||||
* See this for details https://www.sk89q.com/2011/09/Minecraft-name-spoofing-exploit/
|
|
||||||
*
|
|
||||||
* Empty if it's a BungeeCord connection
|
|
||||||
*
|
|
||||||
* @return random generated server id
|
|
||||||
*/
|
|
||||||
public String getServerId() {
|
|
||||||
return serverId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the verify token the server sent to the client.
|
* Gets the verify token the server sent to the client.
|
||||||
*
|
*
|
||||||
@ -64,7 +51,6 @@ public class BukkitLoginSession extends LoginSession {
|
|||||||
return ArrayUtils.clone(verifyToken);
|
return ArrayUtils.clone(verifyToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: this should be optional for players without a skin at all
|
|
||||||
public synchronized Optional<SkinProperties> getSkin() {
|
public synchronized Optional<SkinProperties> getSkin() {
|
||||||
return Optional.ofNullable(skinProperty);
|
return Optional.ofNullable(skinProperty);
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,13 @@ import com.google.common.io.ByteStreams;
|
|||||||
import com.google.common.net.HostAndPort;
|
import com.google.common.net.HostAndPort;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.PluginManager;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.bukkit.plugin.messaging.PluginMessageRecipient;
|
import org.bukkit.plugin.messaging.PluginMessageRecipient;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -35,8 +35,6 @@ import org.slf4j.Logger;
|
|||||||
*/
|
*/
|
||||||
public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<CommandSender> {
|
public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<CommandSender> {
|
||||||
|
|
||||||
//provide a immutable key pair to be thread safe | used for encrypting and decrypting traffic
|
|
||||||
private final KeyPair keyPair = EncryptionUtil.generateKeyPair();
|
|
||||||
private final Logger logger = CommonUtil.createLoggerFromJDK(getLogger());
|
private final Logger logger = CommonUtil.createLoggerFromJDK(getLogger());
|
||||||
|
|
||||||
private boolean bungeeCord;
|
private boolean bungeeCord;
|
||||||
@ -65,6 +63,7 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PluginManager pluginManager = getServer().getPluginManager();
|
||||||
if (bungeeCord) {
|
if (bungeeCord) {
|
||||||
setServerStarted();
|
setServerStarted();
|
||||||
|
|
||||||
@ -77,14 +76,11 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getServer().getPluginManager().isPluginEnabled("ProtocolSupport")) {
|
if (pluginManager.isPluginEnabled("ProtocolSupport")) {
|
||||||
getServer().getPluginManager().registerEvents(new ProtocolSupportListener(this), this);
|
pluginManager.registerEvents(new ProtocolSupportListener(this), this);
|
||||||
} else if (getServer().getPluginManager().isPluginEnabled("ProtocolLib")) {
|
} else if (pluginManager.isPluginEnabled("ProtocolLib")) {
|
||||||
//they will be created with a static builder, because otherwise it will throw a
|
|
||||||
//NoClassDefFoundError: com/comphenix/protocol/events/PacketListener if only ProtocolSupport was found
|
|
||||||
ProtocolLibListener.register(this);
|
ProtocolLibListener.register(this);
|
||||||
|
pluginManager.registerEvents(new SkinApplyListener(this), this);
|
||||||
getServer().getPluginManager().registerEvents(new SkinApplyListener(this), this);
|
|
||||||
} else {
|
} else {
|
||||||
logger.warn("Either ProtocolLib or ProtocolSupport have to be installed if you don't use BungeeCord");
|
logger.warn("Either ProtocolLib or ProtocolSupport have to be installed if you don't use BungeeCord");
|
||||||
}
|
}
|
||||||
@ -93,13 +89,13 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
|||||||
//delay dependency setup because we load the plugin very early where plugins are initialized yet
|
//delay dependency setup because we load the plugin very early where plugins are initialized yet
|
||||||
getServer().getScheduler().runTaskLater(this, new DelayedAuthHook(this), 5L);
|
getServer().getScheduler().runTaskLater(this, new DelayedAuthHook(this), 5L);
|
||||||
|
|
||||||
getServer().getPluginManager().registerEvents(new JoinListener(this), this);
|
pluginManager.registerEvents(new JoinListener(this), this);
|
||||||
|
|
||||||
//register commands using a unique name
|
//register commands using a unique name
|
||||||
getCommand("premium").setExecutor(new PremiumCommand(this));
|
getCommand("premium").setExecutor(new PremiumCommand(this));
|
||||||
getCommand("cracked").setExecutor(new CrackedCommand(this));
|
getCommand("cracked").setExecutor(new CrackedCommand(this));
|
||||||
|
|
||||||
if (getServer().getPluginManager().isPluginEnabled("PlaceholderAPI")) {
|
if (pluginManager.isPluginEnabled("PlaceholderAPI")) {
|
||||||
//prevents NoClassDef errors if it's not available
|
//prevents NoClassDef errors if it's not available
|
||||||
PremiumPlaceholder.register(this);
|
PremiumPlaceholder.register(this);
|
||||||
}
|
}
|
||||||
@ -148,15 +144,6 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
|||||||
return loginSession;
|
return loginSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the server KeyPair. This is used to encrypt or decrypt traffic between the client and server
|
|
||||||
*
|
|
||||||
* @return the server KeyPair
|
|
||||||
*/
|
|
||||||
public KeyPair getServerKey() {
|
|
||||||
return keyPair;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBungeeCord() {
|
public boolean isBungeeCord() {
|
||||||
return bungeeCord;
|
return bungeeCord;
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,10 @@ public class PremiumPlaceholder extends PlaceholderHook {
|
|||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!metadata.isEmpty()) {
|
if (metadata.isEmpty()) {
|
||||||
return "premium";
|
|
||||||
} else {
|
|
||||||
return "cracked";
|
return "cracked";
|
||||||
|
} else {
|
||||||
|
return "premium";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ import de.st_ddt.crazylogin.metadata.Authenticated;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import org.apache.commons.lang.reflect.FieldUtils;
|
import org.apache.commons.lang.reflect.FieldUtils;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@ -29,11 +28,14 @@ public class CrazyLoginHook implements AuthPlugin<Player> {
|
|||||||
|
|
||||||
private final FastLoginBukkit plugin;
|
private final FastLoginBukkit plugin;
|
||||||
|
|
||||||
private final CrazyLogin crazyLoginPlugin = CrazyLogin.getPlugin();
|
private final CrazyLogin crazyLoginPlugin;
|
||||||
private final PlayerListener playerListener = getListener();
|
private final PlayerListener playerListener;
|
||||||
|
|
||||||
public CrazyLoginHook(FastLoginBukkit plugin) {
|
public CrazyLoginHook(FastLoginBukkit plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
||||||
|
crazyLoginPlugin = CrazyLogin.getPlugin();
|
||||||
|
playerListener = getListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -78,7 +80,7 @@ public class CrazyLoginHook implements AuthPlugin<Player> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (InterruptedException | ExecutionException ex) {
|
} catch (InterruptedException | ExecutionException ex) {
|
||||||
plugin.getLogger().log(Level.SEVERE, "Failed to forceLogin", ex);
|
plugin.getLog().error("Failed to forceLogin player: {}", player, ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +114,7 @@ public class CrazyLoginHook implements AuthPlugin<Player> {
|
|||||||
try {
|
try {
|
||||||
listener = (PlayerListener) FieldUtils.readField(crazyLoginPlugin, "playerListener", true);
|
listener = (PlayerListener) FieldUtils.readField(crazyLoginPlugin, "playerListener", true);
|
||||||
} catch (IllegalAccessException ex) {
|
} catch (IllegalAccessException ex) {
|
||||||
plugin.getLogger().log(Level.SEVERE, "Failed to get the listener instance for auto login", ex);
|
plugin.getLog().error("Failed to get the listener instance for auto login", ex);
|
||||||
listener = null;
|
listener = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import com.github.games647.fastlogin.core.hooks.AuthPlugin;
|
|||||||
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -45,7 +44,7 @@ public class UltraAuthHook implements AuthPlugin<Player> {
|
|||||||
try {
|
try {
|
||||||
return future.get();
|
return future.get();
|
||||||
} catch (InterruptedException | ExecutionException ex) {
|
} catch (InterruptedException | ExecutionException ex) {
|
||||||
plugin.getLogger().log(Level.SEVERE, "Failed to forceLogin", ex);
|
plugin.getLog().error("Failed to forceLogin player: {}", player, ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import de.luricos.bukkit.xAuth.xAuthPlayer;
|
|||||||
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -52,7 +51,7 @@ public class xAuthHook implements AuthPlugin<Player> {
|
|||||||
try {
|
try {
|
||||||
return future.get();
|
return future.get();
|
||||||
} catch (InterruptedException | ExecutionException ex) {
|
} catch (InterruptedException | ExecutionException ex) {
|
||||||
plugin.getLogger().log(Level.SEVERE, "Failed to forceLogin", ex);
|
plugin.getLog().error("Failed to forceLogin player: {}", player, ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,7 +79,7 @@ public class xAuthHook implements AuthPlugin<Player> {
|
|||||||
//login in the player after registration
|
//login in the player after registration
|
||||||
return future.get() && forceLogin(player);
|
return future.get() && forceLogin(player);
|
||||||
} catch (InterruptedException | ExecutionException ex) {
|
} catch (InterruptedException | ExecutionException ex) {
|
||||||
plugin.getLogger().log(Level.SEVERE, "Failed to forceLogin", ex);
|
plugin.getLog().error("Failed to forceRegister player: {}", player, ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ public class BungeeListener implements PluginMessageListener {
|
|||||||
new ForceLoginTask(plugin.getCore(), player).run();
|
new ForceLoginTask(plugin.getCore(), player).run();
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
plugin.getLog().error("Failed to query isRegistered", ex);
|
plugin.getLog().error("Failed to query isRegistered for player: {}", player, ex);
|
||||||
}
|
}
|
||||||
}, 20L);
|
}, 20L);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
|||||||
import com.github.games647.fastlogin.core.PlayerProfile;
|
import com.github.games647.fastlogin.core.PlayerProfile;
|
||||||
import com.github.games647.fastlogin.core.shared.JoinManagement;
|
import com.github.games647.fastlogin.core.shared.JoinManagement;
|
||||||
|
|
||||||
|
import java.security.PublicKey;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@ -17,6 +18,7 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
|
|||||||
|
|
||||||
private final FastLoginBukkit plugin;
|
private final FastLoginBukkit plugin;
|
||||||
private final PacketEvent packetEvent;
|
private final PacketEvent packetEvent;
|
||||||
|
private final PublicKey publicKey;
|
||||||
|
|
||||||
private final Random random;
|
private final Random random;
|
||||||
|
|
||||||
@ -24,11 +26,12 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
|
|||||||
private final String username;
|
private final String username;
|
||||||
|
|
||||||
public NameCheckTask(FastLoginBukkit plugin, PacketEvent packetEvent, Random random,
|
public NameCheckTask(FastLoginBukkit plugin, PacketEvent packetEvent, Random random,
|
||||||
Player player, String username) {
|
Player player, String username, PublicKey publicKey) {
|
||||||
super(plugin.getCore(), plugin.getCore().getAuthPluginHook());
|
super(plugin.getCore(), plugin.getCore().getAuthPluginHook());
|
||||||
|
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.packetEvent = packetEvent;
|
this.packetEvent = packetEvent;
|
||||||
|
this.publicKey = publicKey;
|
||||||
this.random = random;
|
this.random = random;
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
@ -37,7 +40,7 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
super.onLogin(username, new ProtocolLibLoginSource(plugin, packetEvent, player, random));
|
super.onLogin(username, new ProtocolLibLoginSource(packetEvent, player, random, publicKey));
|
||||||
} finally {
|
} finally {
|
||||||
ProtocolLibrary.getProtocolManager().getAsynchronousManager().signalPacketTransmission(packetEvent);
|
ProtocolLibrary.getProtocolManager().getAsynchronousManager().signalPacketTransmission(packetEvent);
|
||||||
}
|
}
|
||||||
@ -46,12 +49,12 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
|
|||||||
//Minecraft server implementation
|
//Minecraft server implementation
|
||||||
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L161
|
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L161
|
||||||
@Override
|
@Override
|
||||||
public void requestPremiumLogin(ProtocolLibLoginSource source, PlayerProfile profile
|
public void requestPremiumLogin(ProtocolLibLoginSource source, PlayerProfile profile,
|
||||||
, String username, boolean registered) {
|
String username, boolean registered) {
|
||||||
try {
|
try {
|
||||||
source.setOnlineMode();
|
source.setOnlineMode();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
plugin.getLog().error("Cannot send encryption packet. Falling back to cracked login", ex);
|
plugin.getLog().error("Cannot send encryption packet. Falling back to cracked login for: {}", profile, ex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,10 @@ import com.comphenix.protocol.ProtocolLibrary;
|
|||||||
import com.comphenix.protocol.events.PacketAdapter;
|
import com.comphenix.protocol.events.PacketAdapter;
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
|
import com.github.games647.fastlogin.bukkit.EncryptionUtil;
|
||||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||||
|
|
||||||
|
import java.security.KeyPair;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@ -20,8 +22,10 @@ public class ProtocolLibListener extends PacketAdapter {
|
|||||||
private static final int WORKER_THREADS = 3;
|
private static final int WORKER_THREADS = 3;
|
||||||
|
|
||||||
private final FastLoginBukkit plugin;
|
private final FastLoginBukkit plugin;
|
||||||
|
|
||||||
//just create a new once on plugin enable. This used for verify token generation
|
//just create a new once on plugin enable. This used for verify token generation
|
||||||
private final SecureRandom random = new SecureRandom();
|
private final SecureRandom random = new SecureRandom();
|
||||||
|
private final KeyPair keyPair = EncryptionUtil.generateKeyPair();
|
||||||
|
|
||||||
public ProtocolLibListener(FastLoginBukkit plugin) {
|
public ProtocolLibListener(FastLoginBukkit plugin) {
|
||||||
//run async in order to not block the server, because we are making api calls to Mojang
|
//run async in order to not block the server, because we are making api calls to Mojang
|
||||||
@ -34,6 +38,7 @@ public class ProtocolLibListener extends PacketAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void register(FastLoginBukkit plugin) {
|
public static void register(FastLoginBukkit plugin) {
|
||||||
|
//they will be created with a static builder, because otherwise it will throw a NoClassDefFoundError
|
||||||
ProtocolLibrary.getProtocolManager()
|
ProtocolLibrary.getProtocolManager()
|
||||||
.getAsynchronousManager()
|
.getAsynchronousManager()
|
||||||
.registerAsyncHandler(new ProtocolLibListener(plugin))
|
.registerAsyncHandler(new ProtocolLibListener(plugin))
|
||||||
@ -61,7 +66,7 @@ public class ProtocolLibListener extends PacketAdapter {
|
|||||||
byte[] sharedSecret = packetEvent.getPacket().getByteArrays().read(0);
|
byte[] sharedSecret = packetEvent.getPacket().getByteArrays().read(0);
|
||||||
|
|
||||||
packetEvent.getAsyncMarker().incrementProcessingDelay();
|
packetEvent.getAsyncMarker().incrementProcessingDelay();
|
||||||
Runnable verifyTask = new VerifyResponseTask(plugin, packetEvent, sender, sharedSecret);
|
Runnable verifyTask = new VerifyResponseTask(plugin, packetEvent, sender, sharedSecret, keyPair);
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, verifyTask);
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, verifyTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +84,7 @@ public class ProtocolLibListener extends PacketAdapter {
|
|||||||
plugin.getLog().trace("GameProfile {} with {} connecting", sessionKey, username);
|
plugin.getLog().trace("GameProfile {} with {} connecting", sessionKey, username);
|
||||||
|
|
||||||
packetEvent.getAsyncMarker().incrementProcessingDelay();
|
packetEvent.getAsyncMarker().incrementProcessingDelay();
|
||||||
Runnable nameCheckTask = new NameCheckTask(plugin, packetEvent, random, player, username);
|
Runnable nameCheckTask = new NameCheckTask(plugin, packetEvent, random, player, username, keyPair.getPublic());
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, nameCheckTask);
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, nameCheckTask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import com.comphenix.protocol.events.PacketContainer;
|
|||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||||
import com.github.games647.fastlogin.bukkit.EncryptionUtil;
|
import com.github.games647.fastlogin.bukkit.EncryptionUtil;
|
||||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
|
||||||
import com.github.games647.fastlogin.core.shared.LoginSource;
|
import com.github.games647.fastlogin.core.shared.LoginSource;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
@ -23,31 +22,40 @@ import static com.comphenix.protocol.PacketType.Login.Server.ENCRYPTION_BEGIN;
|
|||||||
|
|
||||||
public class ProtocolLibLoginSource implements LoginSource {
|
public class ProtocolLibLoginSource implements LoginSource {
|
||||||
|
|
||||||
private final FastLoginBukkit plugin;
|
|
||||||
|
|
||||||
private final PacketEvent packetEvent;
|
private final PacketEvent packetEvent;
|
||||||
private final Player player;
|
private final Player player;
|
||||||
|
|
||||||
private final Random random;
|
private final Random random;
|
||||||
|
private final PublicKey publicKey;
|
||||||
|
|
||||||
private String serverId;
|
private final String serverId = "";
|
||||||
private byte[] verifyToken;
|
private byte[] verifyToken;
|
||||||
|
|
||||||
public ProtocolLibLoginSource(FastLoginBukkit plugin, PacketEvent packetEvent, Player player, Random random) {
|
public ProtocolLibLoginSource(PacketEvent packetEvent, Player player, Random random, PublicKey publicKey) {
|
||||||
this.plugin = plugin;
|
|
||||||
this.packetEvent = packetEvent;
|
this.packetEvent = packetEvent;
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.random = random;
|
this.random = random;
|
||||||
|
this.publicKey = publicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOnlineMode() throws Exception {
|
public void setOnlineMode() throws Exception {
|
||||||
//randomized server id to make sure the request is for our server
|
|
||||||
//this could be relevant https://www.sk89q.com/2011/09/minecraft-name-spoofing-exploit/
|
|
||||||
serverId = Long.toString(random.nextLong(), 16);
|
|
||||||
verifyToken = EncryptionUtil.generateVerifyToken(random);
|
verifyToken = EncryptionUtil.generateVerifyToken(random);
|
||||||
|
|
||||||
sentEncryptionRequest();
|
/*
|
||||||
|
* Packet Information: http://wiki.vg/Protocol#Encryption_Request
|
||||||
|
*
|
||||||
|
* ServerID="" (String) key=public server key verifyToken=random 4 byte array
|
||||||
|
*/
|
||||||
|
PacketContainer newPacket = new PacketContainer(ENCRYPTION_BEGIN);
|
||||||
|
|
||||||
|
newPacket.getStrings().write(0, serverId);
|
||||||
|
newPacket.getSpecificModifier(PublicKey.class).write(0, publicKey);
|
||||||
|
|
||||||
|
newPacket.getByteArrays().write(0, verifyToken);
|
||||||
|
|
||||||
|
//serverId is a empty string
|
||||||
|
ProtocolLibrary.getProtocolManager().sendServerPacket(player, newPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -72,24 +80,6 @@ public class ProtocolLibLoginSource implements LoginSource {
|
|||||||
return packetEvent.getPlayer().getAddress();
|
return packetEvent.getPlayer().getAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sentEncryptionRequest() throws InvocationTargetException {
|
|
||||||
/*
|
|
||||||
* Packet Information: http://wiki.vg/Protocol#Encryption_Request
|
|
||||||
*
|
|
||||||
* ServerID="" (String) key=public server key verifyToken=random 4 byte array
|
|
||||||
*/
|
|
||||||
PacketContainer newPacket = new PacketContainer(ENCRYPTION_BEGIN);
|
|
||||||
|
|
||||||
newPacket.getStrings().write(0, serverId);
|
|
||||||
PublicKey publicKey = plugin.getServerKey().getPublic();
|
|
||||||
newPacket.getSpecificModifier(PublicKey.class).write(0, publicKey);
|
|
||||||
|
|
||||||
newPacket.getByteArrays().write(0, verifyToken);
|
|
||||||
|
|
||||||
//serverId is a empty string
|
|
||||||
ProtocolLibrary.getProtocolManager().sendServerPacket(player, newPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getServerId() {
|
public String getServerId() {
|
||||||
return serverId;
|
return serverId;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ public class SkinApplyListener implements Listener {
|
|||||||
try {
|
try {
|
||||||
MethodUtils.invokeMethod(map, "put", new Object[]{SkinProperties.TEXTURE_KEY, skin.getHandle()});
|
MethodUtils.invokeMethod(map, "put", new Object[]{SkinProperties.TEXTURE_KEY, skin.getHandle()});
|
||||||
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
|
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
|
||||||
plugin.getLog().error("Error setting premium skin", ex);
|
plugin.getLog().error("Error setting premium skin of: {}", player, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@ import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.KeyPair;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@ -32,16 +32,19 @@ public class VerifyResponseTask implements Runnable {
|
|||||||
|
|
||||||
private final FastLoginBukkit plugin;
|
private final FastLoginBukkit plugin;
|
||||||
private final PacketEvent packetEvent;
|
private final PacketEvent packetEvent;
|
||||||
|
private final KeyPair serverKey;
|
||||||
|
|
||||||
private final Player player;
|
private final Player player;
|
||||||
|
|
||||||
private final byte[] sharedSecret;
|
private final byte[] sharedSecret;
|
||||||
|
|
||||||
public VerifyResponseTask(FastLoginBukkit plugin, PacketEvent packetEvent, Player player, byte[] sharedSecret) {
|
public VerifyResponseTask(FastLoginBukkit plugin, PacketEvent packetEvent, Player player,
|
||||||
|
byte[] sharedSecret, KeyPair keyPair) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.packetEvent = packetEvent;
|
this.packetEvent = packetEvent;
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.sharedSecret = Arrays.copyOf(sharedSecret, sharedSecret.length);
|
this.sharedSecret = Arrays.copyOf(sharedSecret, sharedSecret.length);
|
||||||
|
this.serverKey = keyPair;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -65,8 +68,7 @@ public class VerifyResponseTask implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void verifyResponse(BukkitLoginSession session) {
|
private void verifyResponse(BukkitLoginSession session) {
|
||||||
PublicKey publicKey = plugin.getServerKey().getPublic();
|
PrivateKey privateKey = serverKey.getPrivate();
|
||||||
PrivateKey privateKey = plugin.getServerKey().getPrivate();
|
|
||||||
|
|
||||||
Cipher cipher;
|
Cipher cipher;
|
||||||
SecretKey loginKey;
|
SecretKey loginKey;
|
||||||
@ -88,10 +90,7 @@ public class VerifyResponseTask implements Runnable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//this makes sure the request from the client is for us
|
String serverId = EncryptionUtil.getServerIdHashString("", loginKey, serverKey.getPublic());
|
||||||
//this might be relevant https://www.sk89q.com/2011/09/minecraft-name-spoofing-exploit/
|
|
||||||
String generatedId = session.getServerId();
|
|
||||||
String serverId = EncryptionUtil.getServerIdHashString(generatedId, loginKey, publicKey);
|
|
||||||
|
|
||||||
String username = session.getUsername();
|
String username = session.getUsername();
|
||||||
if (plugin.getCore().getApiConnector().hasJoinedServer(session, serverId, player.getAddress())) {
|
if (plugin.getCore().getApiConnector().hasJoinedServer(session, serverId, player.getAddress())) {
|
||||||
@ -115,7 +114,7 @@ public class VerifyResponseTask implements Runnable {
|
|||||||
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/NetworkManager.java#L69
|
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/NetworkManager.java#L69
|
||||||
FieldUtils.writeField(networkManager, "spoofedUUID", premiumUUID, true);
|
FieldUtils.writeField(networkManager, "spoofedUUID", premiumUUID, true);
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
plugin.getLog().error("Error setting premium uuid", exc);
|
plugin.getLog().error("Error setting premium uuid of {}", player, exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,7 +187,7 @@ public class VerifyResponseTask implements Runnable {
|
|||||||
//tell the server that we want to close the connection
|
//tell the server that we want to close the connection
|
||||||
player.kickPlayer("Disconnect");
|
player.kickPlayer("Disconnect");
|
||||||
} catch (InvocationTargetException ex) {
|
} catch (InvocationTargetException ex) {
|
||||||
plugin.getLog().error("Error sending kick packet", ex);
|
plugin.getLog().error("Error sending kick packet for: {}", player, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +203,7 @@ public class VerifyResponseTask implements Runnable {
|
|||||||
//we don't want to handle our own packets so ignore filters
|
//we don't want to handle our own packets so ignore filters
|
||||||
ProtocolLibrary.getProtocolManager().recieveClientPacket(player, startPacket, false);
|
ProtocolLibrary.getProtocolManager().recieveClientPacket(player, startPacket, false);
|
||||||
} catch (InvocationTargetException | IllegalAccessException ex) {
|
} catch (InvocationTargetException | IllegalAccessException ex) {
|
||||||
plugin.getLog().warn("Failed to fake a new start packet", 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
|
//cancel the event in order to prevent the server receiving an invalid packet
|
||||||
kickPlayer(plugin.getCore().getMessage("error-kick"));
|
kickPlayer(plugin.getCore().getMessage("error-kick"));
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ public class DelayedAuthHook implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ReflectiveOperationException ex) {
|
} catch (ReflectiveOperationException ex) {
|
||||||
plugin.getLog().error("Couldn't load the integration class", ex);
|
plugin.getLog().error("Couldn't load the auth hook class", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -55,7 +55,7 @@ public class ForceLoginTask extends ForceLoginManagement<Player, CommandSender,
|
|||||||
//the player-list isn't thread-safe
|
//the player-list isn't thread-safe
|
||||||
return Bukkit.getScheduler().callSyncMethod(core.getPlugin(), player::isOnline).get();
|
return Bukkit.getScheduler().callSyncMethod(core.getPlugin(), player::isOnline).get();
|
||||||
} catch (InterruptedException | ExecutionException ex) {
|
} catch (InterruptedException | ExecutionException ex) {
|
||||||
core.getPlugin().getLog().error("Failed to perform thread-safe online check", ex);
|
core.getPlugin().getLog().error("Failed to perform thread-safe online check for {}", player, ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ public class ConnectListener implements Listener {
|
|||||||
idField.setAccessible(true);
|
idField.setAccessible(true);
|
||||||
idField.set(connection, offlineUUID);
|
idField.set(connection, offlineUUID);
|
||||||
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||||
plugin.getLog().error("Failed to set offline uuid", ex);
|
plugin.getLog().error("Failed to set offline uuid of {}", username, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.zaxxer</groupId>
|
<groupId>com.zaxxer</groupId>
|
||||||
<artifactId>HikariCP</artifactId>
|
<artifactId>HikariCP</artifactId>
|
||||||
<version>2.7.7</version>
|
<version>2.7.8</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--Logging framework implements slf4j which is required by hikari-->
|
<!--Logging framework implements slf4j which is required by hikari-->
|
||||||
|
@ -11,6 +11,7 @@ import java.sql.ResultSet;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.ThreadFactory;
|
||||||
@ -93,25 +94,15 @@ public class AuthStorage {
|
|||||||
|
|
||||||
public PlayerProfile loadProfile(String name) {
|
public PlayerProfile loadProfile(String name) {
|
||||||
try (Connection con = dataSource.getConnection();
|
try (Connection con = dataSource.getConnection();
|
||||||
PreparedStatement loadStmt = con.prepareStatement(LOAD_BY_NAME)) {
|
PreparedStatement loadStmt = con.prepareStatement(LOAD_BY_NAME)
|
||||||
|
) {
|
||||||
loadStmt.setString(1, name);
|
loadStmt.setString(1, name);
|
||||||
|
|
||||||
try (ResultSet resultSet = loadStmt.executeQuery()) {
|
try (ResultSet resultSet = loadStmt.executeQuery()) {
|
||||||
if (resultSet.next()) {
|
return parseResult(resultSet).orElseGet(() -> new PlayerProfile(null, name, false, ""));
|
||||||
long userId = resultSet.getInt(1);
|
|
||||||
|
|
||||||
UUID uuid = UUIDTypeAdapter.parseId(resultSet.getString(2));
|
|
||||||
|
|
||||||
boolean premium = resultSet.getBoolean(4);
|
|
||||||
String lastIp = resultSet.getString(5);
|
|
||||||
Instant lastLogin = resultSet.getTimestamp(6).toInstant();
|
|
||||||
return new PlayerProfile(userId, uuid, name, premium, lastIp, lastLogin);
|
|
||||||
} else {
|
|
||||||
return new PlayerProfile(null, name, false, "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (SQLException sqlEx) {
|
} catch (SQLException sqlEx) {
|
||||||
core.getPlugin().getLog().error("Failed to query profile", sqlEx);
|
core.getPlugin().getLog().error("Failed to query profile: {}", name, sqlEx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -119,27 +110,36 @@ public class AuthStorage {
|
|||||||
|
|
||||||
public PlayerProfile loadProfile(UUID uuid) {
|
public PlayerProfile loadProfile(UUID uuid) {
|
||||||
try (Connection con = dataSource.getConnection();
|
try (Connection con = dataSource.getConnection();
|
||||||
PreparedStatement loadStmt = con.prepareStatement(LOAD_BY_UUID)) {
|
PreparedStatement loadStmt = con.prepareStatement(LOAD_BY_UUID)
|
||||||
|
) {
|
||||||
loadStmt.setString(1, UUIDTypeAdapter.toMojangId(uuid));
|
loadStmt.setString(1, UUIDTypeAdapter.toMojangId(uuid));
|
||||||
|
|
||||||
try (ResultSet resultSet = loadStmt.executeQuery()) {
|
try (ResultSet resultSet = loadStmt.executeQuery()) {
|
||||||
if (resultSet.next()) {
|
return parseResult(resultSet).orElse(null);
|
||||||
long userId = resultSet.getInt(1);
|
|
||||||
|
|
||||||
String name = resultSet.getString(3);
|
|
||||||
boolean premium = resultSet.getBoolean(4);
|
|
||||||
String lastIp = resultSet.getString(5);
|
|
||||||
Instant lastLogin = resultSet.getTimestamp(6).toInstant();
|
|
||||||
return new PlayerProfile(userId, uuid, name, premium, lastIp, lastLogin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (SQLException sqlEx) {
|
} catch (SQLException sqlEx) {
|
||||||
core.getPlugin().getLog().error("Failed to query profile", sqlEx);
|
core.getPlugin().getLog().error("Failed to query profile: {}", uuid, sqlEx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Optional<PlayerProfile> parseResult(ResultSet resultSet) throws SQLException {
|
||||||
|
if (resultSet.next()) {
|
||||||
|
long userId = resultSet.getInt(1);
|
||||||
|
|
||||||
|
UUID uuid = UUIDTypeAdapter.parseId(resultSet.getString(2));
|
||||||
|
|
||||||
|
String name = resultSet.getString(3);
|
||||||
|
boolean premium = resultSet.getBoolean(4);
|
||||||
|
String lastIp = resultSet.getString(5);
|
||||||
|
Instant lastLogin = resultSet.getTimestamp(6).toInstant();
|
||||||
|
return Optional.of(new PlayerProfile(userId, uuid, name, premium, lastIp, lastLogin));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
public void save(PlayerProfile playerProfile) {
|
public void save(PlayerProfile playerProfile) {
|
||||||
try (Connection con = dataSource.getConnection()) {
|
try (Connection con = dataSource.getConnection()) {
|
||||||
String uuid = playerProfile.getId().map(UUIDTypeAdapter::toMojangId).orElse(null);
|
String uuid = playerProfile.getId().map(UUIDTypeAdapter::toMojangId).orElse(null);
|
||||||
@ -163,7 +163,6 @@ public class AuthStorage {
|
|||||||
saveStmt.setString(4, playerProfile.getLastIp());
|
saveStmt.setString(4, playerProfile.getLastIp());
|
||||||
|
|
||||||
saveStmt.execute();
|
saveStmt.execute();
|
||||||
|
|
||||||
try (ResultSet generatedKeys = saveStmt.getGeneratedKeys()) {
|
try (ResultSet generatedKeys = saveStmt.getGeneratedKeys()) {
|
||||||
if (generatedKeys != null && generatedKeys.next()) {
|
if (generatedKeys != null && generatedKeys.next()) {
|
||||||
playerProfile.setRowId(generatedKeys.getInt(1));
|
playerProfile.setRowId(generatedKeys.getInt(1));
|
||||||
@ -171,11 +170,9 @@ public class AuthStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
core.getPlugin().getLog().error("Failed to save playerProfile", ex);
|
core.getPlugin().getLog().error("Failed to save playerProfile {}", playerProfile, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
|
@ -7,7 +7,6 @@ import java.util.UUID;
|
|||||||
public class PlayerProfile {
|
public class PlayerProfile {
|
||||||
|
|
||||||
private String playerName;
|
private String playerName;
|
||||||
|
|
||||||
private long rowId;
|
private long rowId;
|
||||||
|
|
||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
@ -48,7 +47,6 @@ public class PlayerProfile {
|
|||||||
this.rowId = generatedId;
|
this.rowId = generatedId;
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: this should be optional
|
|
||||||
public synchronized Optional<UUID> getId() {
|
public synchronized Optional<UUID> getId() {
|
||||||
return Optional.ofNullable(uuid);
|
return Optional.ofNullable(uuid);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -62,13 +61,13 @@ public class MojangApiConnector {
|
|||||||
protected final Gson gson = new GsonBuilder()
|
protected final Gson gson = new GsonBuilder()
|
||||||
.registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create();
|
.registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create();
|
||||||
|
|
||||||
public MojangApiConnector(Logger logger, Collection<String> localAddresses, int rateLimit
|
public MojangApiConnector(Logger logger, Iterable<String> localAddresses, int rateLimit
|
||||||
, Iterable<HostAndPort> proxies) {
|
, Iterable<HostAndPort> proxies) {
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.rateLimit = Math.max(rateLimit, 600);
|
this.rateLimit = Math.max(rateLimit, 600);
|
||||||
this.sslFactory = buildAddresses(logger, localAddresses);
|
this.sslFactory = buildAddresses(logger, localAddresses);
|
||||||
|
|
||||||
List<Proxy> proxyBuilder = new ArrayList<>();
|
Collection<Proxy> proxyBuilder = new ArrayList<>();
|
||||||
for (HostAndPort proxy : proxies) {
|
for (HostAndPort proxy : proxies) {
|
||||||
proxyBuilder.add(new Proxy(Type.HTTP, new InetSocketAddress(proxy.getHostText(), proxy.getPort())));
|
proxyBuilder.add(new Proxy(Type.HTTP, new InetSocketAddress(proxy.getHostText(), proxy.getPort())));
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ public class UUIDTypeAdapter extends TypeAdapter<UUID> {
|
|||||||
|
|
||||||
private static final Pattern UUID_PATTERN = Pattern.compile("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})");
|
private static final Pattern UUID_PATTERN = Pattern.compile("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})");
|
||||||
|
|
||||||
public static UUID parseId(String withoutDashes) {
|
public static UUID parseId(CharSequence withoutDashes) {
|
||||||
return UUID.fromString(UUID_PATTERN.matcher(withoutDashes).replaceAll("$1-$2-$3-$4-$5"));
|
return UUID.fromString(UUID_PATTERN.matcher(withoutDashes).replaceAll("$1-$2-$3-$4-$5"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ import java.util.Collection;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
@ -42,7 +41,7 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
|
|||||||
protected final Map<String, String> localeMessages = new ConcurrentHashMap<>();
|
protected final Map<String, String> localeMessages = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final ConcurrentMap<String, Object> pendingLogin = CommonUtil.buildCache(5, -1);
|
private final ConcurrentMap<String, Object> pendingLogin = CommonUtil.buildCache(5, -1);
|
||||||
private final Set<UUID> pendingConfirms = new HashSet<>();
|
private final Collection<UUID> pendingConfirms = new HashSet<>();
|
||||||
private final T plugin;
|
private final T plugin;
|
||||||
|
|
||||||
private Configuration config;
|
private Configuration config;
|
||||||
|
@ -64,7 +64,7 @@ public abstract class ForceLoginManagement<P extends C, C, L extends LoginSessio
|
|||||||
storage.save(playerProfile);
|
storage.save(playerProfile);
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
core.getPlugin().getLog().warn("ERROR ON FORCE LOGIN", ex);
|
core.getPlugin().getLog().warn("ERROR ON FORCE LOGIN of {}", getName(player), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
core.getPlugin().getLog().error("Failed to check premium state", ex);
|
core.getPlugin().getLog().error("Failed to check premium state of {}", username, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ public abstract class LoginSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public synchronized String toString() {
|
||||||
return this.getClass().getSimpleName() + '{' +
|
return this.getClass().getSimpleName() + '{' +
|
||||||
"username='" + username + '\'' +
|
"username='" + username + '\'' +
|
||||||
", profile=" + profile +
|
", profile=" + profile +
|
||||||
|
Reference in New Issue
Block a user