mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-11-22 10:15:18 +01:00
Merge remote-tracking branch 'origin/inventory-cached' into feargames
This commit is contained in:
commit
ec36e6875e
@ -10,6 +10,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
public class PlayerCache {
|
||||
|
||||
private final Map<String, PlayerAuth> cache = new ConcurrentHashMap<>();
|
||||
private final Map<String, RegistrationStatus> registeredCache = new ConcurrentHashMap<>();
|
||||
|
||||
PlayerCache() {
|
||||
}
|
||||
@ -20,6 +21,7 @@ public class PlayerCache {
|
||||
* @param auth the player auth object to save
|
||||
*/
|
||||
public void updatePlayer(PlayerAuth auth) {
|
||||
registeredCache.put(auth.getNickname().toLowerCase(), RegistrationStatus.REGISTERED);
|
||||
cache.put(auth.getNickname().toLowerCase(), auth);
|
||||
}
|
||||
|
||||
@ -30,6 +32,7 @@ public class PlayerCache {
|
||||
*/
|
||||
public void removePlayer(String user) {
|
||||
cache.remove(user.toLowerCase());
|
||||
registeredCache.remove(user.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -43,6 +46,35 @@ public class PlayerCache {
|
||||
return cache.containsKey(user.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a registration entry to the cache for active use later like the player active playing.
|
||||
*
|
||||
* @param user player name
|
||||
* @param status registration status
|
||||
*/
|
||||
public void addRegistrationStatus(String user, RegistrationStatus status) {
|
||||
registeredCache.put(user.toLowerCase(), status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the status for existing entries like currently active users
|
||||
* @param user player name
|
||||
* @param status newest query result
|
||||
*/
|
||||
public void updateRegistrationStatus(String user, RegistrationStatus status) {
|
||||
registeredCache.replace(user, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is cached result with the player having an account.
|
||||
* <b>Warning: This shouldn't be used for authentication, because the result could be outdated.</b>
|
||||
* @param user player name
|
||||
* @return Cached result about being registered or unregistered and UNKNOWN if there is no cache entry
|
||||
*/
|
||||
public RegistrationStatus getRegistrationStatus(String user) {
|
||||
return registeredCache.getOrDefault(user.toLowerCase(), RegistrationStatus.UNKNOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PlayerAuth associated with the given user, if available.
|
||||
*
|
||||
@ -66,8 +98,13 @@ public class PlayerCache {
|
||||
*
|
||||
* @return all player auths inside the player cache
|
||||
*/
|
||||
public Map<String, PlayerAuth> getCache() {
|
||||
public Map<String, PlayerAuth> getAuthCache() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
public enum RegistrationStatus {
|
||||
REGISTERED,
|
||||
UNREGISTERED,
|
||||
UNKNOWN
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ public class CacheDataSource implements DataSource {
|
||||
|
||||
@Override
|
||||
public List<String> getLoggedPlayersWithEmptyMail() {
|
||||
return playerCache.getCache().values().stream()
|
||||
return playerCache.getAuthCache().values().stream()
|
||||
.filter(auth -> Utils.isEmailEmpty(auth.getEmail()))
|
||||
.map(PlayerAuth::getRealName)
|
||||
.collect(Collectors.toList());
|
||||
|
@ -1,6 +1,7 @@
|
||||
package fr.xephi.authme.listener;
|
||||
|
||||
import fr.xephi.authme.data.auth.PlayerCache;
|
||||
import fr.xephi.authme.data.auth.PlayerCache.RegistrationStatus;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.initialization.SettingsDependent;
|
||||
import fr.xephi.authme.service.ValidationService;
|
||||
@ -17,7 +18,7 @@ import javax.inject.Inject;
|
||||
/**
|
||||
* Service class for the AuthMe listeners to determine whether an event should be canceled.
|
||||
*/
|
||||
class ListenerService implements SettingsDependent {
|
||||
public class ListenerService implements SettingsDependent {
|
||||
|
||||
private final DataSource dataSource;
|
||||
private final PlayerCache playerCache;
|
||||
@ -77,28 +78,34 @@ class ListenerService implements SettingsDependent {
|
||||
* @return true if the associated event should be canceled, false otherwise
|
||||
*/
|
||||
public boolean shouldCancelEvent(Player player) {
|
||||
return player != null && !checkAuth(player.getName()) && !PlayerUtils.isNpc(player);
|
||||
return player != null && !PlayerUtils.isNpc(player) && shouldRestrictPlayer(player.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if restriction are required for the given player name. The check will be performed against the local
|
||||
* cache. This means changes from other sources like web services will have a delay to it.
|
||||
*
|
||||
* @param name player name
|
||||
* @return true if the player needs to be restricted
|
||||
*/
|
||||
public boolean shouldRestrictPlayer(String name) {
|
||||
if (validationService.isUnrestricted(name) || playerCache.isAuthenticated(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isRegistrationForced) {
|
||||
// registration always required to play - so restrict everything
|
||||
return true;
|
||||
}
|
||||
|
||||
// registration not enforced, but registered players needs to be restricted if not logged in
|
||||
// if there is no data fall back to safer alternative to prevent any leakage
|
||||
final RegistrationStatus status = playerCache.getRegistrationStatus(name);
|
||||
return status != RegistrationStatus.UNREGISTERED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(Settings settings) {
|
||||
isRegistrationForced = settings.getProperty(RegistrationSettings.FORCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the player is allowed to perform actions (i.e. whether he is logged in
|
||||
* or if other settings permit playing).
|
||||
*
|
||||
* @param name the name of the player to verify
|
||||
* @return true if the player may play, false otherwise
|
||||
*/
|
||||
private boolean checkAuth(String name) {
|
||||
if (validationService.isUnrestricted(name) || playerCache.isAuthenticated(name)) {
|
||||
return true;
|
||||
}
|
||||
if (!isRegistrationForced && !dataSource.isAuthAvailable(name)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -24,20 +24,21 @@ import com.comphenix.protocol.events.PacketAdapter;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.data.auth.PlayerCache;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.listener.ListenerService;
|
||||
import fr.xephi.authme.output.ConsoleLoggerFactory;
|
||||
import fr.xephi.authme.service.BukkitService;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
class InventoryPacketAdapter extends PacketAdapter {
|
||||
|
||||
private static final int PLAYER_INVENTORY = 0;
|
||||
@ -49,13 +50,12 @@ class InventoryPacketAdapter extends PacketAdapter {
|
||||
private static final int HOTBAR_SIZE = 9;
|
||||
|
||||
private final ConsoleLogger logger = ConsoleLoggerFactory.get(InventoryPacketAdapter.class);
|
||||
private final PlayerCache playerCache;
|
||||
private final DataSource dataSource;
|
||||
|
||||
InventoryPacketAdapter(AuthMe plugin, PlayerCache playerCache, DataSource dataSource) {
|
||||
private final ListenerService listenerService;
|
||||
|
||||
InventoryPacketAdapter(AuthMe plugin, ListenerService listenerService) {
|
||||
super(plugin, PacketType.Play.Server.SET_SLOT, PacketType.Play.Server.WINDOW_ITEMS);
|
||||
this.playerCache = playerCache;
|
||||
this.dataSource = dataSource;
|
||||
this.listenerService = listenerService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -64,7 +64,7 @@ class InventoryPacketAdapter extends PacketAdapter {
|
||||
PacketContainer packet = packetEvent.getPacket();
|
||||
|
||||
int windowId = packet.getIntegers().read(0);
|
||||
if (windowId == PLAYER_INVENTORY && shouldHideInventory(player.getName())) {
|
||||
if (windowId == PLAYER_INVENTORY && listenerService.shouldRestrictPlayer(player.getName())) {
|
||||
packetEvent.setCancelled(true);
|
||||
}
|
||||
}
|
||||
@ -78,14 +78,10 @@ class InventoryPacketAdapter extends PacketAdapter {
|
||||
ProtocolLibrary.getProtocolManager().addPacketListener(this);
|
||||
|
||||
bukkitService.getOnlinePlayers().stream()
|
||||
.filter(player -> shouldHideInventory(player.getName()))
|
||||
.filter(player -> listenerService.shouldRestrictPlayer(player.getName()))
|
||||
.forEach(this::sendBlankInventoryPacket);
|
||||
}
|
||||
|
||||
private boolean shouldHideInventory(String playerName) {
|
||||
return !playerCache.isAuthenticated(playerName) && dataSource.isAuthAvailable(playerName);
|
||||
}
|
||||
|
||||
public void unregister() {
|
||||
ProtocolLibrary.getProtocolManager().removePacketListener(this);
|
||||
}
|
||||
|
@ -1,19 +1,21 @@
|
||||
package fr.xephi.authme.listener.protocollib;
|
||||
|
||||
import ch.jalu.injector.annotations.NoFieldScan;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.data.auth.PlayerCache;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.initialization.SettingsDependent;
|
||||
import fr.xephi.authme.listener.ListenerService;
|
||||
import fr.xephi.authme.output.ConsoleLoggerFactory;
|
||||
import fr.xephi.authme.service.BukkitService;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@NoFieldScan
|
||||
public class ProtocolLibService implements SettingsDependent {
|
||||
|
||||
@ -31,16 +33,16 @@ public class ProtocolLibService implements SettingsDependent {
|
||||
private boolean isEnabled;
|
||||
private final AuthMe plugin;
|
||||
private final BukkitService bukkitService;
|
||||
private final ListenerService listenerService;
|
||||
private final PlayerCache playerCache;
|
||||
private final DataSource dataSource;
|
||||
|
||||
@Inject
|
||||
ProtocolLibService(AuthMe plugin, Settings settings, BukkitService bukkitService, PlayerCache playerCache,
|
||||
DataSource dataSource) {
|
||||
ProtocolLibService(AuthMe plugin, Settings settings, BukkitService bukkitService, ListenerService listenerService,
|
||||
PlayerCache playerCache) {
|
||||
this.plugin = plugin;
|
||||
this.bukkitService = bukkitService;
|
||||
this.listenerService = listenerService;
|
||||
this.playerCache = playerCache;
|
||||
this.dataSource = dataSource;
|
||||
reload(settings);
|
||||
}
|
||||
|
||||
@ -66,7 +68,7 @@ public class ProtocolLibService implements SettingsDependent {
|
||||
if (protectInvBeforeLogin) {
|
||||
if (inventoryPacketAdapter == null) {
|
||||
// register the packet listener and start hiding it for all already online players (reload)
|
||||
inventoryPacketAdapter = new InventoryPacketAdapter(plugin, playerCache, dataSource);
|
||||
inventoryPacketAdapter = new InventoryPacketAdapter(plugin, listenerService);
|
||||
inventoryPacketAdapter.register(bukkitService);
|
||||
}
|
||||
} else if (inventoryPacketAdapter != null) {
|
||||
@ -76,7 +78,7 @@ public class ProtocolLibService implements SettingsDependent {
|
||||
|
||||
if (denyTabCompleteBeforeLogin) {
|
||||
if (tabCompletePacketAdapter == null) {
|
||||
tabCompletePacketAdapter = new TabCompletePacketAdapter(plugin, playerCache);
|
||||
tabCompletePacketAdapter = new TabCompletePacketAdapter(plugin, listenerService);
|
||||
tabCompletePacketAdapter.register();
|
||||
}
|
||||
} else if (tabCompletePacketAdapter != null) {
|
||||
@ -118,8 +120,8 @@ public class ProtocolLibService implements SettingsDependent {
|
||||
public void reload(Settings settings) {
|
||||
boolean oldProtectInventory = this.protectInvBeforeLogin;
|
||||
|
||||
this.protectInvBeforeLogin = settings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN);
|
||||
this.denyTabCompleteBeforeLogin = settings.getProperty(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN);
|
||||
this.protectInvBeforeLogin = settings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN);
|
||||
|
||||
//it was true and will be deactivated now, so we need to restore the inventory for every player
|
||||
if (oldProtectInventory && !protectInvBeforeLogin && inventoryPacketAdapter != null) {
|
||||
|
@ -8,24 +8,26 @@ import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.data.auth.PlayerCache;
|
||||
import fr.xephi.authme.listener.ListenerService;
|
||||
import fr.xephi.authme.output.ConsoleLoggerFactory;
|
||||
|
||||
class TabCompletePacketAdapter extends PacketAdapter {
|
||||
|
||||
private final ConsoleLogger logger = ConsoleLoggerFactory.get(TabCompletePacketAdapter.class);
|
||||
private final PlayerCache playerCache;
|
||||
|
||||
TabCompletePacketAdapter(AuthMe plugin, PlayerCache playerCache) {
|
||||
private final ListenerService listenerService;
|
||||
|
||||
TabCompletePacketAdapter(AuthMe plugin, ListenerService listenerService) {
|
||||
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE);
|
||||
this.playerCache = playerCache;
|
||||
this.listenerService = listenerService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceiving(PacketEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.TAB_COMPLETE) {
|
||||
try {
|
||||
if (!playerCache.isAuthenticated(event.getPlayer().getName())) {
|
||||
String playerName = event.getPlayer().getName();
|
||||
if (listenerService.shouldRestrictPlayer(playerName)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
} catch (FieldAccessException e) {
|
||||
|
@ -2,6 +2,8 @@ package fr.xephi.authme.process.join;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.data.ProxySessionManager;
|
||||
import fr.xephi.authme.data.auth.PlayerCache;
|
||||
import fr.xephi.authme.data.auth.PlayerCache.RegistrationStatus;
|
||||
import fr.xephi.authme.data.limbo.LimboService;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.events.ProtectInventoryEvent;
|
||||
@ -82,6 +84,9 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
||||
@Inject
|
||||
private BungeeSender bungeeSender;
|
||||
|
||||
@Inject
|
||||
private PlayerCache playerCache;
|
||||
|
||||
@Inject
|
||||
private ProxySessionManager proxySessionManager;
|
||||
|
||||
@ -121,17 +126,10 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
||||
}
|
||||
|
||||
final boolean isAuthAvailable = database.isAuthAvailable(name);
|
||||
|
||||
RegistrationStatus status = isAuthAvailable ? RegistrationStatus.REGISTERED : RegistrationStatus.UNREGISTERED;
|
||||
playerCache.addRegistrationStatus(name, status);
|
||||
if (isAuthAvailable) {
|
||||
// Protect inventory
|
||||
if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
|
||||
ProtectInventoryEvent ev = bukkitService.createAndCallEvent(
|
||||
isAsync -> new ProtectInventoryEvent(player, isAsync));
|
||||
if (ev.isCancelled()) {
|
||||
player.updateInventory();
|
||||
logger.fine("ProtectInventoryEvent has been cancelled for " + player.getName() + "...");
|
||||
}
|
||||
}
|
||||
protectInventory(player);
|
||||
|
||||
// Session logic
|
||||
if (sessionService.canResumeSession(player)) {
|
||||
@ -164,6 +162,18 @@ public class AsynchronousJoin implements AsynchronousProcess {
|
||||
processJoinSync(player, isAuthAvailable);
|
||||
}
|
||||
|
||||
private void protectInventory(Player player) {
|
||||
// Protect inventory
|
||||
if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
|
||||
ProtectInventoryEvent ev = bukkitService.createAndCallEvent(
|
||||
isAsync -> new ProtectInventoryEvent(player, isAsync));
|
||||
if (ev.isCancelled()) {
|
||||
player.updateInventory();
|
||||
logger.fine("ProtectInventoryEvent has been cancelled for " + player.getName() + "...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePlayerWithUnmetNameRestriction(Player player, String ip) {
|
||||
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> {
|
||||
player.kickPlayer(service.retrieveSingleMessage(player, MessageKey.NOT_OWNER_ERROR));
|
||||
|
@ -3,6 +3,7 @@ package fr.xephi.authme.service;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||
import fr.xephi.authme.data.auth.PlayerCache;
|
||||
import fr.xephi.authme.data.auth.PlayerCache.RegistrationStatus;
|
||||
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.events.AbstractTeleportEvent;
|
||||
@ -112,7 +113,8 @@ public class TeleportationService implements Reloadable {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.hasPlayedBefore() || !dataSource.isAuthAvailable(player.getName())) {
|
||||
RegistrationStatus registrationStatus = playerCache.getRegistrationStatus(player.getName());
|
||||
if (!player.hasPlayedBefore() || registrationStatus == RegistrationStatus.UNREGISTERED) {
|
||||
logger.debug("Attempting to teleport player `{0}` to first spawn", player.getName());
|
||||
performTeleportation(player, new FirstSpawnTeleportEvent(player, firstSpawn));
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import ch.jalu.injector.testing.BeforeInjecting;
|
||||
import ch.jalu.injector.testing.DelayedInjectionRunner;
|
||||
import ch.jalu.injector.testing.InjectDelayed;
|
||||
import fr.xephi.authme.data.auth.PlayerCache;
|
||||
import fr.xephi.authme.data.auth.PlayerCache.RegistrationStatus;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.service.ValidationService;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
@ -119,6 +120,7 @@ public class ListenerServiceTest {
|
||||
String playerName = "myPlayer1";
|
||||
Player player = mockPlayerWithName(playerName);
|
||||
given(playerCache.isAuthenticated(playerName)).willReturn(false);
|
||||
given(playerCache.getRegistrationStatus(playerName)).willReturn(RegistrationStatus.UNREGISTERED);
|
||||
given(settings.getProperty(RegistrationSettings.FORCE)).willReturn(false);
|
||||
EntityEvent event = mock(EntityEvent.class);
|
||||
given(event.getEntity()).willReturn(player);
|
||||
@ -130,7 +132,7 @@ public class ListenerServiceTest {
|
||||
// then
|
||||
assertThat(result, equalTo(false));
|
||||
verify(playerCache).isAuthenticated(playerName);
|
||||
verify(dataSource).isAuthAvailable(playerName);
|
||||
verify(playerCache).getRegistrationStatus(playerName);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -154,10 +156,9 @@ public class ListenerServiceTest {
|
||||
public void shouldAllowNpcPlayer() {
|
||||
// given
|
||||
String playerName = "other_npc";
|
||||
Player player = mockPlayerWithName(playerName);
|
||||
Player player = mockPlayerWithName(playerName, true);
|
||||
EntityEvent event = mock(EntityEvent.class);
|
||||
given(event.getEntity()).willReturn(player);
|
||||
given(player.hasMetadata("NPC")).willReturn(true);
|
||||
|
||||
// when
|
||||
boolean result = listenerService.shouldCancelEvent(event);
|
||||
@ -214,8 +215,13 @@ public class ListenerServiceTest {
|
||||
}
|
||||
|
||||
private static Player mockPlayerWithName(String name) {
|
||||
return mockPlayerWithName(name,false);
|
||||
}
|
||||
|
||||
private static Player mockPlayerWithName(String name, boolean npc) {
|
||||
Player player = mock(Player.class);
|
||||
given(player.getName()).willReturn(name);
|
||||
given(player.hasMetadata("NPC")).willReturn(npc);
|
||||
return player;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user