Skip to content
Open
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
10 changes: 9 additions & 1 deletion bukkit/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.21.6-R0.1-SNAPSHOT</version>
<!-- configuration-phase plugin messages (PlayerConnection listener overload) -->
<version>1.21.11-R0.1-SNAPSHOT</version>
<scope>provided</scope>
<!-- Use our own newer api version -->
<exclusions>
Expand Down Expand Up @@ -398,5 +399,12 @@
<version>1.80</version>
<scope>test</scope>
</dependency>
<dependency>
<!-- Required to load Paper's JavaPlugin methods in the hook integration tests. -->
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.24.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public class BukkitLoginSession extends LoginSession {
private final ClientPublicKey clientPublicKey;

private boolean verified;
private Boolean preJoinAutoLoginAllowed;
private boolean preJoinLoginQueued;
private SkinProperty skinProperty;

public BukkitLoginSession(String username, byte[] verifyToken, ClientPublicKey publicKey, boolean registered,
Expand Down Expand Up @@ -120,4 +122,20 @@ public synchronized void setVerifiedPremium(boolean verified) {
public synchronized boolean isVerifiedPremium() {
return verified;
}

public synchronized Boolean getPreJoinAutoLoginAllowed() {
return preJoinAutoLoginAllowed;
}

public synchronized void setPreJoinAutoLoginAllowed(boolean allowed) {
this.preJoinAutoLoginAllowed = allowed;
}

public synchronized boolean isPreJoinLoginQueued() {
return preJoinLoginQueued;
}

public synchronized void setPreJoinLoginQueued(boolean queued) {
this.preJoinLoginQueued = queued;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.message.NamespaceKey;
import com.github.games647.fastlogin.core.message.PreJoinMessage;
import fr.xephi.authme.api.v3.AuthMeApi;
import fr.xephi.authme.events.RestoreSessionEvent;
import fr.xephi.authme.process.Management;
Expand All @@ -36,9 +38,13 @@
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredListener;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
* GitHub: <a href="https://github.com/Xephi/AuthMeReloaded/">...</a>
Expand All @@ -56,6 +62,11 @@ public class AuthMeHook implements AuthPlugin<Player>, Listener {
private final AuthMeApi authmeAPI;
private Management authmeManagement;

// AuthMe 6.0+ pre-join dialog support: forceLoginFromProxy(String) on the API
private Method forceLoginFromProxyMethod;
private Object preJoinLoginTarget;
private Method preJoinLoginMethod;

public AuthMeHook(FastLoginBukkit plugin) {
this.plugin = plugin;
this.authmeAPI = AuthMeApi.getInstance();
Expand All @@ -69,6 +80,85 @@ public AuthMeHook(FastLoginBukkit plugin) {
this.authmeManagement = null;
}
}

// Detect AuthMe 6.0+ forceLoginFromProxy(String) API for pre-join dialog compatibility
try {
forceLoginFromProxyMethod = authmeAPI.getClass().getMethod("forceLoginFromProxy", String.class);
preJoinLoginTarget = authmeAPI;
preJoinLoginMethod = forceLoginFromProxyMethod;
} catch (NoSuchMethodException ignored) {
forceLoginFromProxyMethod = null;
}
enablePreJoinSupport();
}

private void enablePreJoinSupport() {
try {
Class<?> configureEvent = Class.forName(
"io.papermc.paper.event.connection.configuration.AsyncPlayerConnectionConfigureEvent");
Class<?> connection = Class.forName("io.papermc.paper.connection.PlayerConnection");
connection.getMethod("isConnected");
Class.forName("io.papermc.paper.connection.PlayerConfigurationConnection")
.getMethod("sendPluginMessage", org.bukkit.plugin.Plugin.class, String.class, byte[].class);
org.bukkit.plugin.messaging.PluginMessageListener.class
.getMethod("onPluginMessageReceived", String.class, connection, byte[].class);
if (preJoinLoginMethod == null && !findLegacyPreJoinQueue(configureEvent)) {
return;
}
AuthMePreJoinListener listener = new AuthMePreJoinListener(plugin, this);
plugin.getServer().getPluginManager().registerEvents(listener, plugin);
if (plugin.getBungeeManager().isEnabled()) {
String channel = NamespaceKey.getCombined(plugin.getName(), PreJoinMessage.CHANNEL);
plugin.getServer().getMessenger().registerIncomingPluginChannel(plugin, channel, listener);
plugin.getServer().getMessenger().registerOutgoingPluginChannel(plugin, channel);
}
plugin.getLog().info("Enabled AuthMe pre-join dialog compatibility");
} catch (ClassNotFoundException | NoSuchMethodException ignored) {
// Older Paper and Spigot keep the ordinary post-join flow.
} catch (ReflectiveOperationException | SecurityException ex) {
plugin.getLog().warn("Could not enable AuthMe pre-join dialog compatibility", ex);
}
}

private boolean findLegacyPreJoinQueue(Class<?> configureEvent) throws ReflectiveOperationException {
Plugin authme = plugin.getServer().getPluginManager().getPlugin("AuthMe");
if (authme == null) {
return false;
}

HandlerList handlers = (HandlerList) configureEvent.getMethod("getHandlerList").invoke(null);
boolean hasAuthMeListener = false;
for (RegisteredListener registration : handlers.getRegisteredListeners()) {
if (registration.getPlugin() != authme) {
continue;
}
hasAuthMeListener = true;
Listener listener = registration.getListener();
try {
// Builds such as 6.0.0-b2734 check this queue before opening either dialog,
// but do not yet expose forceLoginFromProxy(String) on AuthMeApi.
Field sessionsField = listener.getClass().getDeclaredField("proxySessionManager");
sessionsField.setAccessible(true);
Object sessions = sessionsField.get(listener);
if (sessions != null) {
Method queueLogin = sessions.getClass().getMethod("processProxySessionMessage", String.class);
preJoinLoginTarget = sessions;
preJoinLoginMethod = queueLogin;
plugin.getLog().info("Using AuthMe session queue for pre-join dialog compatibility");
return true;
}
} catch (NoSuchFieldException | NoSuchMethodException ignored) {
// Only the dialog listener exposes the shared session queue.
}
}
if (hasAuthMeListener) {
plugin.getLog().warn("AuthMe configuration listener found, but no compatible pre-join login API or queue");
}
return false;
}

public void forceLoginBeforeJoin(String playerName) throws ReflectiveOperationException {
preJoinLoginMethod.invoke(preJoinLoginTarget, playerName);
}

@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
Expand All @@ -84,10 +174,27 @@ public void onSessionRestore(RestoreSessionEvent restoreSessionEvent) {
@Override
public boolean forceLogin(Player player) {
if (authmeAPI.isAuthenticated(player)) {
// AuthMe may have consumed the pre-join request before our delayed task runs.
BukkitLoginSession session = preJoinLoginMethod == null ? null
: plugin.getSession(player.spigot().getRawAddress());
if (session != null && session.isVerifiedPremium() && session.isPreJoinLoginQueued()
&& player.getName().equals(session.getUsername())) {
return true;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
plugin.getLog().warn(ALREADY_AUTHENTICATED, player);
return false;
}

if (plugin.getBungeeManager().isEnabled() && forceLoginFromProxyMethod != null) {
try {
forceLoginBeforeJoin(player.getName());
return true;
} catch (ReflectiveOperationException ex) {
plugin.getLog().warn("Failed to invoke AuthMe forceLoginFromProxy for {}. "
+ "Falling back to standard forceLogin.", player.getName(), ex);
}
}

//skips registration and login
authmeAPI.forceLogin(player);
return true;
Expand Down
Loading