Minestom/src/main/java/net/minestom/server/network/packet/client/login/LoginStartPacket.java

105 lines
4.9 KiB
Java

package net.minestom.server.network.packet.client.login;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.Configuration;
import net.minestom.server.MinecraftServer;
import net.minestom.server.crypto.PlayerPublicKey;
import net.minestom.server.entity.Player;
import net.minestom.server.extras.MojangAuth;
import net.minestom.server.extras.bungee.BungeeCordProxy;
import net.minestom.server.extras.velocity.VelocityProxy;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.packet.server.login.EncryptionRequestPacket;
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
import net.minestom.server.network.packet.server.login.LoginPluginRequestPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.network.player.PlayerSocketConnection;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
public record LoginStartPacket(@NotNull String username, @Nullable PlayerPublicKey publicKey) implements ClientPreplayPacket {
private static final Component ALREADY_CONNECTED = Component.text("You are already on this server", NamedTextColor.RED);
public LoginStartPacket(BinaryReader reader) {
this(reader.readSizedString(16), reader.readBoolean() ?
new PlayerPublicKey(reader) : null);
}
@Override
public void process(@NotNull PlayerConnection connection) {
connection.setPlayerPublicKey(publicKey);
final Configuration config = MinecraftServer.getConfiguration();
if (config.requireValidPlayerPublicKey()) {
if (publicKey != null) {
if (!publicKey.isValid()) {
connection.sendPacket(new LoginDisconnectPacket(config.invalidPlayerPublicKeyMessage()));
connection.disconnect();
}
} else {
connection.sendPacket(new LoginDisconnectPacket(config.missingPlayerPublicKeyMessage()));
connection.disconnect();
}
}
final boolean isSocketConnection = connection instanceof PlayerSocketConnection;
// Proxy support (only for socket clients) and cache the login username
if (isSocketConnection) {
PlayerSocketConnection socketConnection = (PlayerSocketConnection) connection;
socketConnection.UNSAFE_setLoginUsername(username);
// Velocity support
if (VelocityProxy.isEnabled()) {
final int messageId = ThreadLocalRandom.current().nextInt();
final String channel = VelocityProxy.PLAYER_INFO_CHANNEL;
// Important in order to retrieve the channel in the response packet
socketConnection.addPluginRequestEntry(messageId, channel);
connection.sendPacket(new LoginPluginRequestPacket(messageId, channel, null));
return;
}
}
if (MojangAuth.isEnabled() && isSocketConnection) {
// Mojang auth
if (CONNECTION_MANAGER.getPlayer(username) != null) {
connection.sendPacket(new LoginDisconnectPacket(ALREADY_CONNECTED));
connection.disconnect();
return;
}
final PlayerSocketConnection socketConnection = (PlayerSocketConnection) connection;
socketConnection.setConnectionState(ConnectionState.LOGIN);
final byte[] publicKey = MojangAuth.getKeyPair().getPublic().getEncoded();
byte[] nonce = new byte[4];
ThreadLocalRandom.current().nextBytes(nonce);
socketConnection.setNonce(nonce);
socketConnection.sendPacket(new EncryptionRequestPacket("", publicKey, nonce));
} else {
final boolean bungee = BungeeCordProxy.isEnabled();
// Offline
final UUID playerUuid = bungee && isSocketConnection ?
((PlayerSocketConnection) connection).getBungeeUuid() :
CONNECTION_MANAGER.getPlayerConnectionUuid(connection, username);
Player player = CONNECTION_MANAGER.startPlayState(connection, playerUuid, username, true);
if (bungee && isSocketConnection) {
player.setSkin(((PlayerSocketConnection) connection).getBungeeSkin());
}
}
}
@Override
public void write(@NotNull BinaryWriter writer) {
if (username.length() > 16)
throw new IllegalArgumentException("Username is not allowed to be longer than 16 characters");
writer.writeSizedString(username);
writer.writeNullable(publicKey);
}
}