Fix race condition with Bukkit join handling where players are denied entry but subsequently login slightly later

This commit is contained in:
Luck 2017-03-05 00:59:44 +00:00
parent b20b03113a
commit 53c9e5bb4a
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B

View File

@ -39,17 +39,23 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.scheduler.BukkitTask;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
class BukkitListener extends AbstractListener implements Listener {
private final LPBukkitPlugin plugin;
private final Set<UUID> deniedAsyncLogin = Collections.synchronizedSet(new HashSet<>());
private final Set<UUID> deniedLogin = new HashSet<>();
private final Map<UUID, BukkitTask> cleanupTasks = Collections.synchronizedMap(new HashMap<>());
BukkitListener(LPBukkitPlugin plugin) {
super(plugin);
this.plugin = plugin;
@ -71,20 +77,33 @@ class BukkitListener extends AbstractListener implements Listener {
return;
}
// remove any pending cleanup tasks
BukkitTask task = cleanupTasks.remove(e.getUniqueId());
if (task != null) {
task.cancel();
}
// Process login
onAsyncLogin(e.getUniqueId(), e.getName());
}
@EventHandler(priority = EventPriority.MONITOR)
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerPreLoginMonitor(AsyncPlayerPreLoginEvent e) {
// If they were denied before/at LOW, then don't bother handling here.
if (deniedAsyncLogin.remove(e.getUniqueId())) {
// this is a problem, as they were denied at low priority, but are now being allowed.
if (e.getLoginResult() == AsyncPlayerPreLoginEvent.Result.ALLOWED) {
new IllegalStateException("Player connection was re-allowed for " + e.getUniqueId()).printStackTrace();
e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, "");
}
return;
}
// Login event was cancelled by another plugin
if (plugin.isStarted() && plugin.getStorage().isAcceptingLogins() && e.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
onLeave(e.getUniqueId());
cleanupUser(e.getUniqueId());
}
}
@ -107,6 +126,12 @@ class BukkitListener extends AbstractListener implements Listener {
return;
}
// remove any pending cleanup tasks
BukkitTask task = cleanupTasks.remove(e.getPlayer().getUniqueId());
if (task != null) {
task.cancel();
}
try {
// Make a new permissible for the user
LPPermissible lpPermissible = new LPPermissible(player, user, plugin);
@ -120,24 +145,29 @@ class BukkitListener extends AbstractListener implements Listener {
plugin.refreshAutoOp(player);
// We assume all users are not op, but those who are need extra calculation.
if (player.isOp()) {
// We assume all users are not op, but those who are need extra calculation.
plugin.doAsync(() -> user.getUserData().preCalculate(plugin.getPreProcessContexts(true)));
}
}
@EventHandler(priority = EventPriority.MONITOR)
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerLoginMonitor(PlayerLoginEvent e) {
if (e.getResult() != PlayerLoginEvent.Result.ALLOWED) {
// If they were denied before/at LOW, then don't bother handling here.
if (deniedLogin.remove(e.getPlayer().getUniqueId())) {
// If they were denied before/at LOW, then don't bother handling here.
if (deniedLogin.remove(e.getPlayer().getUniqueId())) {
return;
// this is a problem, as they were denied at low priority, but are now being allowed.
if (e.getResult() == PlayerLoginEvent.Result.ALLOWED) {
new IllegalStateException("Player connection was re-allowed for " + e.getPlayer().getUniqueId()).printStackTrace();
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, "");
}
return;
}
if (e.getResult() != PlayerLoginEvent.Result.ALLOWED) {
// The player got denied on sync login.
plugin.getServer().getScheduler().runTaskLater(plugin, () -> onLeave(e.getPlayer().getUniqueId()), 20L);
cleanupUser(e.getPlayer().getUniqueId());
} else {
plugin.refreshAutoOp(e.getPlayer());
}
@ -160,6 +190,19 @@ class BukkitListener extends AbstractListener implements Listener {
onLeave(player.getUniqueId());
}
private void cleanupUser(UUID uuid) {
if (cleanupTasks.containsKey(uuid)) {
return;
}
BukkitTask task = plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
onLeave(uuid);
cleanupTasks.remove(uuid);
}, 60L);
cleanupTasks.put(uuid, task);
}
@EventHandler
public void onPlayerCommand(PlayerCommandPreprocessEvent e) {
if (plugin.getConfiguration().get(ConfigKeys.OPS_ENABLED)) {