fix: do not allow fetching cookies inside the PlayerProvider, kick player in some login failure cases

This commit is contained in:
mworzala 2024-11-03 00:11:21 -04:00 committed by Matt Worzala
parent 2df89f23c9
commit 2ae8986ff9
2 changed files with 17 additions and 2 deletions

View File

@ -198,8 +198,13 @@ public final class LoginListener {
throw new UnsupportedOperationException("Only socket");
final GameProfile gameProfile = socketConnection.gameProfile();
assert gameProfile != null;
final Player player = MinecraftServer.getConnectionManager().createPlayer(connection, gameProfile);
executeConfig(player, true);
try {
final Player player = MinecraftServer.getConnectionManager().createPlayer(connection, gameProfile);
executeConfig(player, true);
} catch (Throwable t) {
MinecraftServer.getExceptionManager().handleException(t);
connection.kick(ERROR_DURING_LOGIN);
}
}
public static void configAckListener(@NotNull ClientConfigurationAckPacket packet, @NotNull Player player) {
@ -236,6 +241,7 @@ public final class LoginListener {
MinecraftServer.getConnectionManager().doConfiguration(player, isFirstConfig);
} catch (Throwable t) {
MinecraftServer.getExceptionManager().handleException(t);
player.kick(ERROR_DURING_LOGIN);
}
});
}

View File

@ -211,6 +211,15 @@ public abstract class PlayerConnection {
}
public CompletableFuture<byte @Nullable []> fetchCookie(@NotNull String key) {
if (getConnectionState() == ConnectionState.CONFIGURATION && getPlayer() == null) {
// This is a bit of an unfortunate limitation. The player provider blocks the player read virtual
// thread waiting for the player provider so a cookie response would never be received and the
// process would deadlock.
// We cannot create the player provider without blocking the read thread because the client
// has already sent the initial settings packet, and we need the Player to process the response.
// We could store the settings on the connection, but it does not seem worth to get around this case.
throw new IllegalStateException("Cannot fetch cookie in PlayerProvider, use AsyncPlayerPreLoginEvent or AsyncPlayerConfigurationEvent");
}
CompletableFuture<byte[]> future = new CompletableFuture<>();
pendingCookieRequests.put(NamespaceID.from(key), future);
sendPacket(new CookieRequestPacket(key));