Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ You can also create your own translation file and, if you want, you can share it
<li>Compatible with Minecraft mods like <strong>BuildCraft or RedstoneCraft</strong></li>
<li>Graphical login/register dialogs, with optional Paper/Folia pre-join dialogs</li>
<li>Restricted users (associate a username with an IP)</li>
<li>Protect player's inventory until correct authentication (requires ProtocolLib)</li>
<li>Protect player's inventory until correct authentication (requires PacketEvents)</li>
<li>Saves the quit location of the player</li>
<li>Automatic database backup</li>
<li>Available languages: <a href="https://github.com/AuthMe/AuthMeReloaded/blob/master/docs/translations.md">translations</a></li>
Expand Down Expand Up @@ -142,7 +142,7 @@ AuthMe can display graphical login/register dialogs instead of chat-based prompt
> - `AuthMe-*-Spigot-1.21.jar` (Spigot 1.20.x – 1.21.x)
> - `AuthMe-*-Paper.jar` (Paper 1.21+)
> - `AuthMe-*-Folia.jar` (Folia 1.21+)
>- ProtocolLib (optional, required by some features)
>- PacketEvents (optional, required by some features)

## Credits

Expand Down
4 changes: 2 additions & 2 deletions authme-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@
<artifactId>bstats-bukkit</artifactId>
</dependency>
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<groupId>com.github.retrooper</groupId>
<artifactId>packetevents-spigot</artifactId>
</dependency>
<dependency>
<groupId>net.luckperms</groupId>
Expand Down
2 changes: 2 additions & 0 deletions authme-core/src/main/java/fr/xephi/authme/AuthMe.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import fr.xephi.authme.platform.CommandRegistrationAdapter;
import fr.xephi.authme.platform.DialogAdapter;
import fr.xephi.authme.platform.EventRegistrationAdapter;
import fr.xephi.authme.platform.PacketInterceptionAdapter;
import fr.xephi.authme.platform.PlatformAdapter;
import fr.xephi.authme.platform.TeleportAdapter;

Expand Down Expand Up @@ -222,6 +223,7 @@ private void initialize(PlatformAdapter platformAdapter) {
injector.register(SchedulingAdapter.class, platformAdapter);
injector.register(DialogAdapter.class, platformAdapter);
injector.register(CommandRegistrationAdapter.class, platformAdapter);
injector.register(PacketInterceptionAdapter.class, platformAdapter);

// Get settings and set up logger
settings = injector.getSingleton(Settings.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.listener.protocollib.ProtocolLibService;
import fr.xephi.authme.listener.packetevents.PacketEventsService;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.service.PluginHookService;
import fr.xephi.authme.settings.SpawnLoader;
Expand All @@ -26,7 +26,7 @@ public class ServerListener implements Listener {
@Inject
private SpawnLoader spawnLoader;
@Inject
private ProtocolLibService protocolLibService;
private PacketEventsService packetEventsService;
@Inject
private PermissionsManager permissionsManager;

Expand All @@ -50,9 +50,9 @@ public void onPluginDisable(PluginDisableEvent event) {
} else if ("EssentialsSpawn".equalsIgnoreCase(pluginName)) {
spawnLoader.unloadEssentialsSpawn();
logger.info("EssentialsSpawn has been disabled: unhooking");
} else if ("ProtocolLib".equalsIgnoreCase(pluginName)) {
protocolLibService.disable();
logger.warning("ProtocolLib has been disabled, unhooking packet adapters!");
} else if ("packetevents".equalsIgnoreCase(pluginName)) {
packetEventsService.disable();
logger.warning("PacketEvents has been disabled, unhooking packet listeners!");
}
}

Expand All @@ -72,8 +72,8 @@ public void onPluginEnable(PluginEnableEvent event) {
} else if ("CMI".equalsIgnoreCase(pluginName)) {
pluginHookService.tryHookToCmi();
spawnLoader.loadCmiSpawn();
} else if ("ProtocolLib".equalsIgnoreCase(pluginName)) {
protocolLibService.setup();
} else if ("packetevents".equalsIgnoreCase(pluginName)) {
packetEventsService.setup();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package fr.xephi.authme.listener.packetevents;

import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetSlot;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerWindowItems;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import org.bukkit.entity.Player;

import java.util.Collections;

public class InventoryPacketListener extends PacketListenerAbstract {

private static final int PLAYER_INVENTORY = 0;
// Crafting (5) + Armor (4) + Main inventory (27) + Hotbar (9) = 45 slots
private static final int INVENTORY_SIZE = 45;

private final ConsoleLogger logger = ConsoleLoggerFactory.get(InventoryPacketListener.class);
private final PlayerCache playerCache;
private final DataSource dataSource;

public InventoryPacketListener(PlayerCache playerCache, DataSource dataSource) {
this.playerCache = playerCache;
this.dataSource = dataSource;
}

@Override
public void onPacketSend(PacketSendEvent event) {
if (event.getPacketType() == PacketType.Play.Server.WINDOW_ITEMS) {
if (new WrapperPlayServerWindowItems(event).getWindowId() == PLAYER_INVENTORY) {
cancelIfShouldHide(event);
}
} else if (event.getPacketType() == PacketType.Play.Server.SET_SLOT) {
if (new WrapperPlayServerSetSlot(event).getWindowId() == PLAYER_INVENTORY) {
cancelIfShouldHide(event);
}
}
}

private void cancelIfShouldHide(PacketSendEvent event) {
Player player = event.getPlayer();
if (player != null && !playerCache.isAuthenticated(player.getName())
&& dataSource.isAuthAvailable(player.getName())) {
event.setCancelled(true);
}
}

public void sendBlankInventoryPacket(Player player) {
WrapperPlayServerWindowItems packet = new WrapperPlayServerWindowItems(
PLAYER_INVENTORY, 0,
Collections.nCopies(INVENTORY_SIZE, ItemStack.EMPTY),
ItemStack.EMPTY
);
try {
PacketEvents.getAPI().getPlayerManager().sendPacket(player, packet);
} catch (Exception e) {
logger.logException("Error during sending blank inventory", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package fr.xephi.authme.listener.packetevents;

import com.github.retrooper.packetevents.PacketEvents;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.platform.PacketInterceptionAdapter;
import org.bukkit.entity.Player;

/**
* PacketEvents-backed implementation of {@link PacketInterceptionAdapter}.
* Instantiated lazily so PacketEvents classes are only resolved when the dependency is available.
*/
public final class PacketEventsListenerRegistry implements PacketInterceptionAdapter {

private InventoryPacketListener inventoryPacketListener;
private TabCompletePacketListener tabCompletePacketListener;

@Override
public void registerInventoryProtection(PlayerCache playerCache, DataSource dataSource) {
if (inventoryPacketListener == null) {
inventoryPacketListener = new InventoryPacketListener(playerCache, dataSource);
}
PacketEvents.getAPI().getEventManager().registerListener(inventoryPacketListener);
}

@Override
public void unregisterInventoryProtection() {
if (inventoryPacketListener != null) {
PacketEvents.getAPI().getEventManager().unregisterListener(inventoryPacketListener);
inventoryPacketListener = null;
}
}

@Override
public void sendBlankInventoryPacket(Player player) {
if (inventoryPacketListener != null) {
inventoryPacketListener.sendBlankInventoryPacket(player);
}
}

@Override
public void registerTabCompleteBlock(PlayerCache playerCache) {
if (tabCompletePacketListener == null) {
tabCompletePacketListener = new TabCompletePacketListener(playerCache);
}
PacketEvents.getAPI().getEventManager().registerListener(tabCompletePacketListener);
}

@Override
public void unregisterTabCompleteBlock() {
if (tabCompletePacketListener != null) {
PacketEvents.getAPI().getEventManager().unregisterListener(tabCompletePacketListener);
tabCompletePacketListener = null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package fr.xephi.authme.listener.packetevents;

import ch.jalu.injector.annotations.NoFieldScan;
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.output.ConsoleLoggerFactory;
import fr.xephi.authme.platform.PacketInterceptionAdapter;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

import javax.inject.Inject;

@NoFieldScan
public class PacketEventsService implements SettingsDependent {

private final ConsoleLogger logger = ConsoleLoggerFactory.get(PacketEventsService.class);

private boolean protectInvBeforeLogin;
private boolean denyTabCompleteBeforeLogin;
private boolean inventoryProtectionRegistered;
private boolean tabCompleteBlockRegistered;

private final BukkitService bukkitService;
private final PlayerCache playerCache;
private final DataSource dataSource;
private final PacketInterceptionAdapter packetInterceptionAdapter;

@Inject
PacketEventsService(Settings settings, BukkitService bukkitService, PlayerCache playerCache,
DataSource dataSource, PacketInterceptionAdapter packetInterceptionAdapter) {
this.bukkitService = bukkitService;
this.playerCache = playerCache;
this.dataSource = dataSource;
this.packetInterceptionAdapter = packetInterceptionAdapter;
reload(settings);
}

/**
* Sets up the PacketEvents packet listeners.
*/
public void setup() {
if (!Bukkit.getPluginManager().isPluginEnabled("packetevents")) {
if (protectInvBeforeLogin) {
logger.warning("WARNING! The protectInventory feature requires PacketEvents! Disabling it...");
}
if (denyTabCompleteBeforeLogin) {
logger.warning("WARNING! The denyTabComplete feature requires PacketEvents! Disabling it...");
}
return;
}

if (protectInvBeforeLogin) {
if (!inventoryProtectionRegistered) {
packetInterceptionAdapter.registerInventoryProtection(playerCache, dataSource);
inventoryProtectionRegistered = true;
// Send blank packets to online unauthenticated players (reload scenario)
for (Player player : bukkitService.getOnlinePlayers()) {
if (!playerCache.isAuthenticated(player.getName())
&& dataSource.isAuthAvailable(player.getName())) {
packetInterceptionAdapter.sendBlankInventoryPacket(player);
}
}
}
} else if (inventoryProtectionRegistered) {
packetInterceptionAdapter.unregisterInventoryProtection();
inventoryProtectionRegistered = false;
}

if (denyTabCompleteBeforeLogin) {
if (!tabCompleteBlockRegistered) {
packetInterceptionAdapter.registerTabCompleteBlock(playerCache);
tabCompleteBlockRegistered = true;
}
} else if (tabCompleteBlockRegistered) {
packetInterceptionAdapter.unregisterTabCompleteBlock();
tabCompleteBlockRegistered = false;
}
}

/**
* Stops all PacketEvents-based features.
*/
public void disable() {
if (inventoryProtectionRegistered) {
packetInterceptionAdapter.unregisterInventoryProtection();
inventoryProtectionRegistered = false;
}
if (tabCompleteBlockRegistered) {
packetInterceptionAdapter.unregisterTabCompleteBlock();
tabCompleteBlockRegistered = false;
}
}

/**
* Sends a blank inventory packet to the given player.
*
* @param player the player to send the blank inventory to
*/
public void sendBlankInventoryPacket(Player player) {
if (inventoryProtectionRegistered) {
packetInterceptionAdapter.sendBlankInventoryPacket(player);
}
}

@Override
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);

// If inventory protection was on and is now disabled, restore inventories for online players
if (oldProtectInventory && !protectInvBeforeLogin && inventoryProtectionRegistered) {
packetInterceptionAdapter.unregisterInventoryProtection();
inventoryProtectionRegistered = false;
for (Player onlinePlayer : bukkitService.getOnlinePlayers()) {
if (!playerCache.isAuthenticated(onlinePlayer.getName())) {
onlinePlayer.updateInventory();
}
}
}
setup();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package fr.xephi.authme.listener.packetevents;

import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import fr.xephi.authme.data.auth.PlayerCache;
import org.bukkit.entity.Player;

public class TabCompletePacketListener extends PacketListenerAbstract {

private final PlayerCache playerCache;

public TabCompletePacketListener(PlayerCache playerCache) {
this.playerCache = playerCache;
}

@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.TAB_COMPLETE) {
Player player = event.getPlayer();
if (player != null && !playerCache.isAuthenticated(player.getName())) {
event.setCancelled(true);
}
}
}
}
Loading
Loading