Added BungeeCord support

This commit is contained in:
games647
2015-11-13 22:46:38 +01:00
parent 834818bb7a
commit c3f8e59a9a
16 changed files with 527 additions and 78 deletions

View File

@ -1,3 +1,9 @@
#####0.3
* Added BungeeCord support
* Decrease timeout checks in order to fail faster on connection problems
* Code style improvements
######0.2.4
* Fixed NPE on invalid sessions

View File

@ -10,7 +10,10 @@ So they don't need to enter passwords. This is also called auto login.
* Automatically login paid accounts (premium)
* Support various of auth plugins
* Experimental Cauldron support
* BungeeCord support
* No client modifications needed
* Good performance by async non blocking operations
* Free
***
@ -114,16 +117,22 @@ and Mojang account. Then the command can be executed. So someone different canno
by buying the username.
####Does the plugin have BungeeCord support?
Not yet, but I'm planning this.
Yes it has. Just activate ipForward in your BungeeCord config and place the plugin in the plugins folder of
Bukkit/Spigot and BungeeCord. This plugin will automatically detect if BungeeCord is running and so handle checks
there.
####Could premium players have a premium UUID and Skin?
Something like that is possible, but is not yet implemented.
####Is this plugin compatible with Cauldron?
It's not yet tested, but all needed methods also exists in Cauldron so it could work together
It's not tested yet, but all needed methods also exists in Cauldron so it could work together.
***
###Useful Links:
* [Login Protocol](http://wiki.vg/Protocol#Login)
* [Protocol Encryption](http://wiki.vg/Protocol_Encryption)
* [Protocol Encryption](http://wiki.vg/Protocol_Encryption)
###Donate
[![Donate Button](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8ZBULMAPN7MZC)

99
bungee/pom.xml Normal file
View File

@ -0,0 +1,99 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.games647</groupId>
<!--This have to be in lowercase because it's used by plugin.yml-->
<artifactId>fastloginbungee</artifactId>
<packaging>jar</packaging>
<name>FastLogin</name>
<version>0.1</version>
<inceptionYear>2015</inceptionYear>
<url>https://github.com/games647/FastLogin</url>
<description>
Automatically logins premium (paid accounts) player on a offline mode server
</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!--Possibility to deploy directly to the plugins folder-->
<outputDir>${basedir}/target</outputDir>
</properties>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/games647/FastLogin/issues</url>
</issueManagement>
<scm>
<url>https://github.com/games647/FastLogin</url>
<connection>scm:git:git://github.com/games647/FastLogin.git</connection>
<developerConnection>scm:git:ssh://git@github.com:games647/FastLogin.git</developerConnection>
</scm>
<build>
<defaultGoal>install</defaultGoal>
<!--Just use the project name to replace an old version of the plugin if the user does only copy-paste-->
<finalName>${project.name}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
<!--false means actual true http://jira.codehaus.org/browse/MCOMPILER-209-->
<useIncrementalCompilation>false</useIncrementalCompilation>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<outputDirectory>${outputDir}</outputDirectory>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<!--Replace variables-->
<filtering>true</filtering>
</resource>
<!--Add the license to jar in order to see it in the final jar-->
<resource>
<directory>${basedir}</directory>
<includes>
<include>LICENSE</include>
</includes>
</resource>
</resources>
</build>
<repositories>
<!-- BungeeCord -->
<repository>
<id>bungeecord-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.8-SNAPSHOT</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,34 @@
package com.github.games647.fastloginbungee;
import com.google.common.collect.Sets;
import java.util.Set;
import net.md_5.bungee.api.plugin.Plugin;
/**
* BungeeCord version of FastLogin. This plugin keeps track
* on online mode connections.
*/
public class FastLogin extends Plugin {
private final Set<String> enabledPremium = Sets.newConcurrentHashSet();
@Override
public void onEnable() {
//events
getProxy().getPluginManager().registerListener(this, new PlayerConnectionListener(this));
//commands
getProxy().getPluginManager().registerCommand(this, new PremiumCommand(this));
}
/**
* A set of players who want to use fastlogin
*
* @return all player which want to be in onlinemode
*/
public Set<String> getEnabledPremium() {
return enabledPremium;
}
}

View File

@ -0,0 +1,78 @@
package com.github.games647.fastloginbungee;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import java.util.UUID;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.PreLoginEvent;
import net.md_5.bungee.api.event.ServerConnectedEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
/**
* Enables online mode logins for specified users and sends
* plugin message to the Bukkit version of this plugin in
* order to clear that the connection is online mode.
*/
public class PlayerConnectionListener implements Listener {
private final FastLogin plugin;
public PlayerConnectionListener(FastLogin plugin) {
this.plugin = plugin;
}
@EventHandler
public void onPreLogin(PreLoginEvent preLoginEvent) {
if (preLoginEvent.isCancelled()) {
return;
}
PendingConnection connection = preLoginEvent.getConnection();
String username = connection.getName();
//just enable it for activated users
if (plugin.getEnabledPremium().contains(username)) {
connection.setOnlineMode(true);
}
}
@EventHandler
public void onServerConnected(ServerConnectedEvent serverConnectedEvent) {
ProxiedPlayer player = serverConnectedEvent.getPlayer();
//send message even when the online mode is activated by default
if (player.getPendingConnection().isOnlineMode()) {
Server server = serverConnectedEvent.getServer();
ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput();
//subchannel name
dataOutput.writeUTF("Checked");
//proxy identifier to check if it's a acceptable proxy
UUID proxyId = UUID.fromString(plugin.getProxy().getConfig().getUuid());
dataOutput.writeLong(proxyId.getMostSignificantBits());
dataOutput.writeLong(proxyId.getLeastSignificantBits());
//Data is sent through a random player. We have to tell the Bukkit version of this plugin the target
dataOutput.writeUTF(player.getName());
server.sendData(plugin.getDescription().getName(), dataOutput.toByteArray());
}
}
@EventHandler
public void onPluginMessage(PluginMessageEvent pluginMessageEvent) {
String channel = pluginMessageEvent.getTag();
if (pluginMessageEvent.isCancelled() || !plugin.getDescription().getName().equals(channel)) {
return;
}
//the client shouldn't be able to read the messages in order to know something about server internal states
//moreover the client shouldn't be able fake a running premium check by sending the result message
pluginMessageEvent.setCancelled(true);
}
}

View File

@ -0,0 +1,38 @@
package com.github.games647.fastloginbungee;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
/**
* Let players activate the fastlogin method on a BungeeCord instance.
*/
public class PremiumCommand extends Command {
private final FastLogin plugin;
public PremiumCommand(FastLogin plugin) {
super(plugin.getDescription().getName()
, plugin.getDescription().getName() + ".command." + "premium"
, "prem" , "premium", "loginfast");
this.plugin = plugin;
}
@Override
public void execute(CommandSender sender, String[] args) {
if (!(sender instanceof ProxiedPlayer)) {
sender.sendMessage(new ComponentBuilder("Only player can invoke this command")
.color(ChatColor.DARK_RED)
.create());
return;
}
plugin.getEnabledPremium().add(sender.getName());
sender.sendMessage(new ComponentBuilder("Added to the list of premium players")
.color(ChatColor.DARK_GREEN)
.create());
}
}

View File

@ -0,0 +1,12 @@
# project informations for BungeeCord
# This file will be prioritised over plugin.yml which can be also used for Bungee
# This make it easy to combine BungeeCord and Bukkit support in one plugin
name: ${project.name}
# ${...} will be automatically replaced by Maven
main: ${project.groupId}.${project.artifactId}.${project.name}
version: ${project.version}
author: games647, http://github.com/games647/FastLogin/graphs/contributors
description: |
${project.description}

View File

@ -8,7 +8,7 @@
<packaging>jar</packaging>
<name>FastLogin</name>
<version>0.2.4</version>
<version>0.3</version>
<inceptionYear>2015</inceptionYear>
<url>https://github.com/games647/FastLogin</url>
<description>

View File

@ -1,13 +1,16 @@
package com.github.games647.fastlogin;
import com.github.games647.fastlogin.listener.PlayerListener;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.utility.SafeCacheBuilder;
import com.github.games647.fastlogin.hooks.AuthPlugin;
import com.github.games647.fastlogin.listener.BukkitJoinListener;
import com.github.games647.fastlogin.listener.BungeeCordListener;
import com.github.games647.fastlogin.listener.EncryptionPacketListener;
import com.github.games647.fastlogin.listener.HandshakePacketListener;
import com.github.games647.fastlogin.listener.StartPacketListener;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Sets;
import com.google.common.reflect.ClassPath;
@ -20,16 +23,16 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
/**
* This plugin checks if a player has a paid account and if so
* tries to skip offline mode authentication.
* This plugin checks if a player has a paid account and if so tries to skip offline mode authentication.
*/
public class FastLogin extends JavaPlugin {
//http connection, read timeout and user agent for a connection to mojang api servers
private static final int TIMEOUT = 10 * 1000;
private static final int TIMEOUT = 1 * 1000;
private static final String USER_AGENT = "Premium-Checker";
//provide a immutable key pair to be thread safe | used for encrypting and decrypting traffic
@ -38,11 +41,14 @@ public class FastLogin extends JavaPlugin {
//we need a thread-safe set because we access it async in the packet listener
private final Set<String> enabledPremium = Sets.newConcurrentHashSet();
//player=fake player created by Protocollib | this mapmaker creates a concurrent map with weak keys
private final ConcurrentMap<Player, Object> bungeeCordUsers = new MapMaker().weakKeys().makeMap();
//this map is thread-safe for async access (Packet Listener)
//SafeCacheBuilder is used in order to be version independent
private final ConcurrentMap<String, PlayerSession> session = SafeCacheBuilder.<String, PlayerSession>newBuilder()
//2 minutes should be enough as a timeout for bad internet connection (Server, Client and Mojang)
.expireAfterWrite(2, TimeUnit.MINUTES)
.expireAfterWrite(1, TimeUnit.MINUTES)
//mapped by ip:port -> PlayerSession
.build(new CacheLoader<String, PlayerSession>() {
@ -72,11 +78,15 @@ public class FastLogin extends JavaPlugin {
//register packet listeners on success
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
protocolManager.addPacketListener(new EncryptionPacketListener(this, protocolManager));
protocolManager.addPacketListener(new HandshakePacketListener(this));
protocolManager.addPacketListener(new StartPacketListener(this, protocolManager));
protocolManager.addPacketListener(new EncryptionPacketListener(this, protocolManager));
//register commands using a unique name
getCommand("premium").setExecutor(new PremiumCommand(this));
//check for incoming messages from the bungeecord version of this plugin
getServer().getMessenger().registerIncomingPluginChannel(this, this.getName(), new BungeeCordListener(this));
}
@Override
@ -84,11 +94,12 @@ public class FastLogin extends JavaPlugin {
//clean up
session.clear();
enabledPremium.clear();
bungeeCordUsers.clear();
}
/**
* Gets a thread-safe map about players which are connecting to the server are being
* checked to be premium (paid account)
* Gets a thread-safe map about players which are connecting to the server
* are being checked to be premium (paid account)
*
* @return a thread-safe session map
*/
@ -97,8 +108,20 @@ public class FastLogin extends JavaPlugin {
}
/**
* Gets the server KeyPair. This is used to encrypt or decrypt traffic between
* the client and server
* Gets a concurrent map with weak keys for all bungeecord users
* which could be detected. It's mapped by a fake instance of player
* created by Protocollib and a non-null raw object.
*
* Represents a similar set collection
*
* @return
*/
public ConcurrentMap<Player, Object> getBungeeCordUsers() {
return bungeeCordUsers;
}
/**
* Gets the server KeyPair. This is used to encrypt or decrypt traffic between the client and server
*
* @return the server KeyPair
*/
@ -166,7 +189,7 @@ public class FastLogin extends JavaPlugin {
}
//We found a supporting plugin - we can now register a forwarding listener to skip authentication from them
getServer().getPluginManager().registerEvents(new PlayerListener(this, authPluginHook), this);
getServer().getPluginManager().registerEvents(new BukkitJoinListener(this, authPluginHook), this);
return true;
}
}

View File

@ -1,5 +1,7 @@
package com.github.games647.fastlogin;
import org.apache.commons.lang.ArrayUtils;
/**
* Represents a client connecting to the server.
*
@ -15,7 +17,7 @@ public class PlayerSession {
public PlayerSession(String username, String serverId, byte[] verifyToken) {
this.username = username;
this.serverId = serverId;
this.verifyToken = verifyToken;
this.verifyToken = ArrayUtils.clone(verifyToken);
}
/**
@ -37,7 +39,7 @@ public class PlayerSession {
* @return the verify token from the server
*/
public byte[] getVerifyToken() {
return verifyToken;
return ArrayUtils.clone(verifyToken);
}
/**

View File

@ -0,0 +1,53 @@
package com.github.games647.fastlogin.listener;
import com.github.games647.fastlogin.FastLogin;
import com.github.games647.fastlogin.PlayerSession;
import com.github.games647.fastlogin.hooks.AuthPlugin;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
/**
* This listener tells authentication plugins if the player has a premium account and we checked it successfully. So the
* plugin can skip authentication.
*/
public class BukkitJoinListener implements Listener {
private static final long DELAY_LOGIN = 2 * 20L;
protected final FastLogin plugin;
protected final AuthPlugin authPlugin;
public BukkitJoinListener(FastLogin plugin, AuthPlugin authPlugin) {
this.plugin = plugin;
this.authPlugin = authPlugin;
}
@EventHandler(ignoreCancelled = true)
public void onJoin(PlayerJoinEvent joinEvent) {
final Player player = joinEvent.getPlayer();
Bukkit.getScheduler().runTaskLater(plugin, new Runnable() {
@Override
public void run() {
String address = player.getAddress().toString();
//removing the session because we now use it
PlayerSession session = plugin.getSessions().remove(address);
//check if it's the same player as we checked before
if (player.isOnline() && session != null
&& player.getName().equals(session.getUsername()) && session.isVerified()) {
plugin.getLogger().log(Level.FINE, "Logging player {0} in", player.getName());
authPlugin.forceLogin(player);
}
}
//Wait before auth plugin and we received a message from BungeeCord initializes the player
}, DELAY_LOGIN);
}
}

View File

@ -0,0 +1,90 @@
package com.github.games647.fastlogin.listener;
import com.github.games647.fastlogin.FastLogin;
import com.github.games647.fastlogin.PlayerSession;
import com.google.common.base.Charsets;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import java.util.logging.Level;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
/**
* Responsible for receiving messages from a BungeeCord instance.
*
* This class also receives the plugin message from the bungeecord version of this plugin in order to
* get notified if the connection is in online mode.
*/
public class BungeeCordListener implements PluginMessageListener {
private static final String FILE_NAME = "proxy-whitelist.txt";
private final FastLogin plugin;
//null if whitelist is empty so bungeecord support is disabled
private final UUID proxyId;
public BungeeCordListener(FastLogin plugin) {
this.plugin = plugin;
this.proxyId = loadBungeeCordId();
}
@Override
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
if (!channel.equals(plugin.getName())) {
return;
}
ByteArrayDataInput dataInput = ByteStreams.newDataInput(message);
String subchannel = dataInput.readUTF();
plugin.getLogger().log(Level.FINEST, "Received plugin message for subchannel {0} from {1}"
, new Object[]{subchannel, player});
if ("Checked".equalsIgnoreCase(subchannel)) {
//bungeecord UUID
long mostSignificantBits = dataInput.readLong();
long leastSignificantBits = dataInput.readLong();
UUID sourceId = new UUID(mostSignificantBits, leastSignificantBits);
//fails too if no proxy id is specified in the whitelist file
if (sourceId.equals(proxyId)) {
//make sure the proxy is allowed to transfer data to us
String playerName = dataInput.readUTF();
//check if the player is still online or disconnected
Player checkedPlayer = plugin.getServer().getPlayerExact(playerName);
if (checkedPlayer != null && checkedPlayer.isOnline()) {
PlayerSession playerSession = new PlayerSession(playerName, null, null);
playerSession.setVerified(true);
//put it only if the user doesn't has a session open
//so that the player have to send the bungeecord packet and cannot skip the verification then
plugin.getSessions().putIfAbsent(checkedPlayer.getAddress().toString(), playerSession);
}
}
}
}
public UUID loadBungeeCordId() {
File whitelistFile = new File(plugin.getDataFolder(), FILE_NAME);
//create a new folder if it doesn't exist. Fail silently otherwise
whitelistFile.getParentFile().mkdir();
try {
if (!whitelistFile.exists()) {
whitelistFile.createNewFile();
}
String firstLine = Files.readFirstLine(whitelistFile, Charsets.UTF_8);
if (firstLine != null && !firstLine.isEmpty()) {
return UUID.fromString(firstLine.trim());
}
} catch (IOException ex) {
plugin.getLogger().log(Level.SEVERE, "Failed to create file for Proxy whitelist", ex);
} catch (Exception ex) {
plugin.getLogger().log(Level.SEVERE, "Failed to retrieve proxy Id. Disabling BungeeCord support", ex);
}
return null;
}
}

View File

@ -147,11 +147,11 @@ public class EncryptionPacketListener extends PacketAdapter {
//try to get the networkManager from ProtocolLib
private Object getNetworkManager(Player player)
throws IllegalAccessException, NoSuchFieldException {
Object injector = TemporaryPlayerFactory.getInjectorFromPlayer(player);
Field injectorField = injector.getClass().getDeclaredField("injector");
Object socketInjector = TemporaryPlayerFactory.getInjectorFromPlayer(player);
Field injectorField = socketInjector.getClass().getDeclaredField("injector");
injectorField.setAccessible(true);
Object rawInjector = injectorField.get(injector);
Object rawInjector = injectorField.get(socketInjector);
injectorField = rawInjector.getClass().getDeclaredField("networkManager");
injectorField.setAccessible(true);
@ -236,7 +236,7 @@ public class EncryptionPacketListener extends PacketAdapter {
//fake a new login packet in order to let the server handle all the other stuff
private void receiveFakeStartPacket(String username, Player from) {
//see StartPacketListener for packet information
PacketContainer startPacket = protocolManager.createPacket(PacketType.Login.Client.START, true);
PacketContainer startPacket = protocolManager.createPacket(PacketType.Login.Client.START);
//uuid is ignored by the packet definition
WrappedGameProfile fakeProfile = new WrappedGameProfile(UUID.randomUUID(), username);

View File

@ -0,0 +1,58 @@
package com.github.games647.fastlogin.listener;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.github.games647.fastlogin.FastLogin;
import java.util.logging.Level;
/**
* Listens to incoming handshake packets.
*
* As BungeeCord sends additional information on the Handshake,
* we can detect it and check so if the player is coming from a
* BungeeCord instance. IpForward has to be activated in the
* BungeeCord config to send these extra information.
*
* Packet information:
* http://wiki.vg/Protocol#Handshake
*
* Int=Protocol version
* String=connecting server address (and additional information from BungeeCord)
* int=server port
* int=next state
*/
public class HandshakePacketListener extends PacketAdapter {
//hides the inherit Plugin plugin field, but we need a more detailed type than just Plugin
private final FastLogin plugin;
public HandshakePacketListener(FastLogin plugin) {
//run async in order to not block the server, because we are making api calls to Mojang
super(params(plugin, PacketType.Handshake.Client.SET_PROTOCOL).optionAsync());
this.plugin = plugin;
}
@Override
public void onPacketReceiving(PacketEvent packetEvent) {
PacketContainer packet = packetEvent.getPacket();
PacketType.Protocol nextProtocol = packet.getProtocols().read(0);
//we don't want to listen for server ping.
if (nextProtocol == PacketType.Protocol.LOGIN) {
//here are the information written separated by a space
String hostname = packet.getStrings().read(0);
//https://hub.spigotmc.org/stash/projects/SPIGOT/repos/spigot/browse/CraftBukkit-Patches/0055-BungeeCord-Support.patch
String[] split = hostname.split("\00");
if (split.length == 3 || split.length == 4) {
plugin.getLogger().log(Level.FINER, "Detected BungeeCord for {0}", hostname);
//object = because there are no concurrent sets with weak keys
plugin.getBungeeCordUsers().put(packetEvent.getPlayer(), new Object());
}
}
}
}

View File

@ -1,54 +0,0 @@
package com.github.games647.fastlogin.listener;
import com.github.games647.fastlogin.FastLogin;
import com.github.games647.fastlogin.PlayerSession;
import com.github.games647.fastlogin.hooks.AuthPlugin;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
/**
* This listener tells authentication plugins if the player
* has a premium account and we checked it successfully. So the
* plugin can skip authentication.
*/
public class PlayerListener implements Listener {
private static final long DELAY_LOGIN = 1 * 20L;
private final FastLogin plugin;
private final AuthPlugin authPlugin;
public PlayerListener(FastLogin plugin, AuthPlugin authPlugin) {
this.plugin = plugin;
this.authPlugin = authPlugin;
}
@EventHandler(ignoreCancelled = true)
public void onJoin(PlayerJoinEvent joinEvent) {
final Player player = joinEvent.getPlayer();
String address = player.getAddress().toString();
//removing the session because we now use it
PlayerSession session = plugin.getSessions().remove(address);
//check if it's the same player as we checked before
if (session != null && player.getName().equals(session.getUsername()) && session.isVerified()) {
Bukkit.getScheduler().runTaskLater(plugin, new Runnable() {
@Override
public void run() {
if (player.isOnline()) {
plugin.getLogger().log(Level.FINE, "Logging player {0} in", player.getName());
authPlugin.forceLogin(player);
}
}
//Wait before auth plugin initializes the player
}, DELAY_LOGIN);
}
}
}

View File

@ -68,7 +68,7 @@ public class StartPacketListener extends PacketAdapter {
*/
@Override
public void onPacketReceiving(PacketEvent packetEvent) {
Player player = packetEvent.getPlayer();
final Player player = packetEvent.getPlayer();
//this includes ip:port. Should be unique for an incoming login request with a timeout of 2 minutes
String sessionKey = player.getAddress().toString();
@ -81,7 +81,8 @@ public class StartPacketListener extends PacketAdapter {
String username = packet.getGameProfiles().read(0).getName();
plugin.getLogger().log(Level.FINER, "Player {0} with {1} connecting to the server"
, new Object[]{sessionKey, username});
if (plugin.getEnabledPremium().contains(username) && isPremiumName(username)) {
if (!plugin.getBungeeCordUsers().containsKey(player)
&& plugin.getEnabledPremium().contains(username) && isPremiumName(username)) {
//minecraft server implementation
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L161
sentEncryptionRequest(sessionKey, username, player, packetEvent);
@ -117,7 +118,7 @@ public class StartPacketListener extends PacketAdapter {
* key=public server key
* verifyToken=random 4 byte array
*/
PacketContainer newPacket = protocolManager.createPacket(PacketType.Login.Server.ENCRYPTION_BEGIN, true);
PacketContainer newPacket = protocolManager.createPacket(PacketType.Login.Server.ENCRYPTION_BEGIN);
//randomized server id to make sure the request is for our server
//this could be relevant http://www.sk89q.com/2011/09/minecraft-name-spoofing-exploit/