package net.minecraft.network; import java.io.IOException; import java.io.Serializable; import java.net.InetAddress; import java.net.Socket; import java.security.PrivateKey; import java.security.PublicKey; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.logging.Logger; import javax.crypto.SecretKey; import cpw.mods.fml.common.network.FMLNetworkHandler; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.network.packet.NetHandler; import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.Packet1Login; import net.minecraft.network.packet.Packet205ClientCommand; import net.minecraft.network.packet.Packet250CustomPayload; import net.minecraft.network.packet.Packet252SharedKey; import net.minecraft.network.packet.Packet253ServerAuthData; import net.minecraft.network.packet.Packet254ServerPing; import net.minecraft.network.packet.Packet255KickDisconnect; import net.minecraft.network.packet.Packet2ClientProtocol; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServerListenThread; import net.minecraft.server.management.ServerConfigurationManager; import net.minecraft.util.StringUtils; public class NetLoginHandler extends NetHandler { /** The 4 byte verify token read from a Packet252SharedKey */ private byte[] verifyToken; /** The Minecraft logger. */ public static Logger logger = Logger.getLogger("Minecraft"); /** The Random object used to generate serverId hex strings. */ private static Random rand = new Random(); public TcpConnection myTCPConnection; public boolean connectionComplete = false; /** Reference to the MinecraftServer object. */ private MinecraftServer mcServer; private int connectionTimer = 0; public String clientUsername = null; private volatile boolean field_72544_i = false; /** server ID that is randomly generated by this login handler. */ private String loginServerId = ""; private boolean field_92028_k = false; /** Secret AES key obtained from the client's Packet252SharedKey */ private SecretKey sharedKey = null; public NetLoginHandler(MinecraftServer par1MinecraftServer, Socket par2Socket, String par3Str) throws IOException { this.mcServer = par1MinecraftServer; this.myTCPConnection = new TcpConnection(par2Socket, par3Str, this, par1MinecraftServer.getKeyPair().getPrivate()); this.myTCPConnection.field_74468_e = 0; } /** * Logs the user in if a login packet is found, otherwise keeps processing network packets unless the timeout has * occurred. */ public void tryLogin() { if (this.field_72544_i) { this.initializePlayerConnection(); } if (this.connectionTimer++ == 6000) { this.raiseErrorAndDisconnect("Took too long to log in"); } else { this.myTCPConnection.processReadPackets(); } } public void raiseErrorAndDisconnect(String par1Str) { try { logger.info("Disconnecting " + this.getUsernameAndAddress() + ": " + par1Str); this.myTCPConnection.addToSendQueue(new Packet255KickDisconnect(par1Str)); this.myTCPConnection.serverShutdown(); this.connectionComplete = true; } catch (Exception var3) { var3.printStackTrace(); } } public void handleClientProtocol(Packet2ClientProtocol par1Packet2ClientProtocol) { this.clientUsername = par1Packet2ClientProtocol.getUsername(); if (!this.clientUsername.equals(StringUtils.stripControlCodes(this.clientUsername))) { this.raiseErrorAndDisconnect("Invalid username!"); } else { PublicKey var2 = this.mcServer.getKeyPair().getPublic(); if (par1Packet2ClientProtocol.getProtocolVersion() != 51) { if (par1Packet2ClientProtocol.getProtocolVersion() > 51) { this.raiseErrorAndDisconnect("Outdated server!"); } else { this.raiseErrorAndDisconnect("Outdated client!"); } } else { this.loginServerId = this.mcServer.isServerInOnlineMode() ? Long.toString(rand.nextLong(), 16) : "-"; this.verifyToken = new byte[4]; rand.nextBytes(this.verifyToken); this.myTCPConnection.addToSendQueue(new Packet253ServerAuthData(this.loginServerId, var2, this.verifyToken)); } } } public void handleSharedKey(Packet252SharedKey par1Packet252SharedKey) { PrivateKey var2 = this.mcServer.getKeyPair().getPrivate(); this.sharedKey = par1Packet252SharedKey.getSharedKey(var2); if (!Arrays.equals(this.verifyToken, par1Packet252SharedKey.getVerifyToken(var2))) { this.raiseErrorAndDisconnect("Invalid client reply"); } this.myTCPConnection.addToSendQueue(new Packet252SharedKey()); } public void handleClientCommand(Packet205ClientCommand par1Packet205ClientCommand) { if (par1Packet205ClientCommand.forceRespawn == 0) { if (this.field_92028_k) { this.raiseErrorAndDisconnect("Duplicate login"); return; } this.field_92028_k = true; if (this.mcServer.isServerInOnlineMode()) { (new ThreadLoginVerifier(this)).start(); } else { this.field_72544_i = true; } } } public void handleLogin(Packet1Login par1Packet1Login) { FMLNetworkHandler.handleLoginPacketOnServer(this, par1Packet1Login); } /** * on success the specified username is connected to the minecraftInstance, otherwise they are packet255'd */ public void initializePlayerConnection() { FMLNetworkHandler.onConnectionReceivedFromClient(this, this.mcServer, this.myTCPConnection.getSocketAddress(), this.clientUsername); } public void completeConnection(String var1) { if (var1 != null) { this.raiseErrorAndDisconnect(var1); } else { EntityPlayerMP var2 = this.mcServer.getConfigurationManager().createPlayerForUser(this.clientUsername); if (var2 != null) { this.mcServer.getConfigurationManager().initializeConnectionToPlayer(this.myTCPConnection, var2); } } this.connectionComplete = true; } public void handleErrorMessage(String par1Str, Object[] par2ArrayOfObj) { logger.info(this.getUsernameAndAddress() + " lost connection"); this.connectionComplete = true; } /** * Handle a server ping packet. */ public void handleServerPing(Packet254ServerPing par1Packet254ServerPing) { try { ServerConfigurationManager var2 = this.mcServer.getConfigurationManager(); String var3 = null; if (par1Packet254ServerPing.field_82559_a == 1) { List var4 = Arrays.asList(new Serializable[] {Integer.valueOf(1), Integer.valueOf(51), this.mcServer.getMinecraftVersion(), this.mcServer.getMOTD(), Integer.valueOf(var2.getCurrentPlayerCount()), Integer.valueOf(var2.getMaxPlayers())}); Object var6; for (Iterator var5 = var4.iterator(); var5.hasNext(); var3 = var3 + var6.toString().replaceAll("\u0000", "")) { var6 = var5.next(); if (var3 == null) { var3 = "\u00a7"; } else { var3 = var3 + "\u0000"; } } } else { var3 = this.mcServer.getMOTD() + "\u00a7" + var2.getCurrentPlayerCount() + "\u00a7" + var2.getMaxPlayers(); } InetAddress var8 = null; if (this.myTCPConnection.getSocket() != null) { var8 = this.myTCPConnection.getSocket().getInetAddress(); } this.myTCPConnection.addToSendQueue(new Packet255KickDisconnect(var3)); this.myTCPConnection.serverShutdown(); if (var8 != null && this.mcServer.getNetworkThread() instanceof DedicatedServerListenThread) { ((DedicatedServerListenThread)this.mcServer.getNetworkThread()).func_71761_a(var8); } this.connectionComplete = true; } catch (Exception var7) { var7.printStackTrace(); } } /** * Default handler called for packets that don't have their own handlers in NetClientHandler; currentlly does * nothing. */ public void unexpectedPacket(Packet par1Packet) { this.raiseErrorAndDisconnect("Protocol error"); } public String getUsernameAndAddress() { return this.clientUsername != null ? this.clientUsername + " [" + this.myTCPConnection.getSocketAddress().toString() + "]" : this.myTCPConnection.getSocketAddress().toString(); } /** * determine if it is a server handler */ public boolean isServerHandler() { return true; } /** * Returns the server Id randomly generated by this login handler. */ static String getServerId(NetLoginHandler par0NetLoginHandler) { return par0NetLoginHandler.loginServerId; } /** * Returns the reference to Minecraft Server. */ static MinecraftServer getLoginMinecraftServer(NetLoginHandler par0NetLoginHandler) { return par0NetLoginHandler.mcServer; } /** * Return the secret AES sharedKey */ static SecretKey getSharedKey(NetLoginHandler par0NetLoginHandler) { return par0NetLoginHandler.sharedKey; } /** * Returns the connecting client username. */ static String getClientUsername(NetLoginHandler par0NetLoginHandler) { return par0NetLoginHandler.clientUsername; } public static boolean func_72531_a(NetLoginHandler par0NetLoginHandler, boolean par1) { return par0NetLoginHandler.field_72544_i = par1; } public void handleCustomPayload(Packet250CustomPayload par1Packet250CustomPayload) { FMLNetworkHandler.handlePacket250Packet(par1Packet250CustomPayload, myTCPConnection, this); } @Override public void handleVanilla250Packet(Packet250CustomPayload payload) { // NOOP for login } public EntityPlayer getPlayer() { return null; }; }