SetupHandlerSupplier interface

Пакет: com.hypixel.hytale.server.core.io.handlers.login

Файл: com/hypixel/hytale/server/core/io/handlers/login/PasswordPacketHandler.java

Методы (1)

МодификаторыВозвратСигнатура
abstract PacketHandler createPacketHandler create(ChannelConnection var1, ProtocolVersion var2, String var3, PlayerAuthentication var4)

Исходный код

Показать/скрыть
class="kw">package com.hypixel.hytale.server.core.io.handlers.login;

class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.hypixel.hytale.protocol.ToServerPacket;
class="kw">import com.hypixel.hytale.protocol.io.ChannelConnection;
class="kw">import com.hypixel.hytale.protocol.io.ConnectionHandler;
class="kw">import com.hypixel.hytale.protocol.packets.auth.PasswordAccepted;
class="kw">import com.hypixel.hytale.protocol.packets.auth.PasswordRejected;
class="kw">import com.hypixel.hytale.protocol.packets.auth.PasswordResponse;
class="kw">import com.hypixel.hytale.protocol.packets.connection.ClientDisconnect;
class="kw">import com.hypixel.hytale.server.core.HytaleServer;
class="kw">import com.hypixel.hytale.server.core.HytaleServerConfig;
class="kw">import com.hypixel.hytale.server.core.Message;
class="kw">import com.hypixel.hytale.server.core.auth.PlayerAuthentication;
class="kw">import com.hypixel.hytale.server.core.io.PacketHandler;
class="kw">import com.hypixel.hytale.server.core.io.ProtocolVersion;
class="kw">import com.hypixel.hytale.server.core.io.handlers.GenericConnectionPacketHandler;
class="kw">import java.nio.charset.StandardCharsets;
class="kw">import java.security.MessageDigest;
class="kw">import java.security.NoSuchAlgorithmException;
class="kw">import java.security.SecureRandom;
class="kw">import java.util.logging.Level;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;

class="kw">public class PasswordPacketHandler class="kw">extends GenericConnectionPacketHandler {
   class="kw">private class="kw">static class="kw">final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
   class="kw">private class="kw">static class="kw">final int MAX_PASSWORD_ATTEMPTS = 3;
   class="kw">private class="kw">static class="kw">final int CHALLENGE_LENGTH = 32;
   @Nonnull
   class="kw">private class="kw">final PlayerAuthentication pendingAuth;
   class="kw">private byte[] passwordChallenge;
   class="kw">private class="kw">final PasswordPacketHandler.SetupHandlerSupplier setupHandlerSupplier;
   class="kw">private int attemptsRemaining = 3;

   class="kw">public PasswordPacketHandler(
      @Nonnull ChannelConnection var1,
      @Nonnull ProtocolVersion var2,
      @Nonnull String var3,
      @Nonnull PlayerAuthentication var4,
      @Nullable byte[] var5,
      @Nonnull PasswordPacketHandler.SetupHandlerSupplier var6
   ) {
      super(var1, var2, var3);
      this.pendingAuth = var4;
      this.passwordChallenge = var5;
      this.setupHandlerSupplier = var6;
   }

   @Nonnull
   @Override
   class="kw">public String getIdentifier() {
      class="kw">return "{Password(" + this.getChannel().formatRemoteAddress() + "), " + this.pendingAuth.getUsername() + "}";
   }

   @Override
   class="kw">public void registered0(ConnectionHandler var1) {
      HytaleServerConfig.TimeoutProfile var2 = HytaleServer.get().getConfig().getConnectionTimeouts();
      if (this.passwordChallenge != null && this.passwordChallenge.length != 0) {
         LOGGER.at(Level.FINE).log("Waiting for password response from %s", this.pendingAuth.getUsername());
         this.enterStage("password", var2.getPassword(), () -> !this.registered);
      } else {
         LOGGER.at(Level.FINE).log("No password required for %s, proceeding to setup", this.pendingAuth.getUsername());
         this.proceedToSetup();
      }
   }

   @Override
   class="kw">public void accept(@Nonnull ToServerPacket var1) {
      class="kw">switch (var1.getId()) {
         case 1:
            this.handle((ClientDisconnect)var1);
            break;
         case 15:
            this.handle((PasswordResponse)var1);
            break;
         class="kw">default:
            this.disconnect(Message.translation("client.general.disconnect.protocol.unexpectedPacket").param("packetId", var1.getId()));
      }
   }

   class="kw">public void handle(@Nonnull ClientDisconnect var1) {
      this.disconnectReason.setClientDisconnectType(var1.type);
      LOGGER.at(Level.INFO)
         .log(
            "%s (%s) at %s left with reason: %s - %s",
            this.pendingAuth.getUuid(),
            this.pendingAuth.getUsername(),
            this.getChannel().formatRemoteAddress(),
            var1.type.name(),
            var1.reason.name()
         );
      this.getChannel().closeApplicationConnection();
   }

   class="kw">public void handle(@Nonnull PasswordResponse var1) {
      this.clearTimeout();
      if (this.passwordChallenge != null && this.passwordChallenge.length != 0) {
         byte[] var2 = var1.hash;
         if (var2 != null && var2.length != 0) {
            String var3 = HytaleServer.get().getConfig().getPassword();
            if (var3 != null && !var3.isEmpty()) {
               byte[] var4 = computePasswordHash(this.passwordChallenge, var3);
               if (var4 == null) {
                  LOGGER.at(Level.SEVERE).log("Failed to compute password hash");
                  this.disconnect(Message.translation("client.general.disconnect.serverError"));
               } else if (!MessageDigest.isEqual(var4, var2)) {
                  this.attemptsRemaining--;
                  LOGGER.at(Level.WARNING)
                     .log(
                        "Invalid password from %s (%s), %d attempts remaining",
                        this.pendingAuth.getUsername(),
                        this.getChannel().formatRemoteAddress(),
                        this.attemptsRemaining
                     );
                  if (this.attemptsRemaining <= 0) {
                     this.disconnect(Message.translation("client.general.disconnect.tooManyPasswordAttempts"));
                  } else {
                     this.passwordChallenge = generateChallenge();
                     this.write(new PasswordRejected(this.passwordChallenge, this.attemptsRemaining));
                     HytaleServerConfig.TimeoutProfile var5 = HytaleServer.get().getConfig().getConnectionTimeouts();
                     this.continueStage("password", var5.getPassword(), () -> !this.registered);
                  }
               } else {
                  LOGGER.at(Level.INFO).log("Password accepted for %s (%s)", this.pendingAuth.getUsername(), this.pendingAuth.getUuid());
                  this.write(new PasswordAccepted());
                  this.proceedToSetup();
               }
            } else {
               LOGGER.at(Level.SEVERE).log("Password validation failed - no password configured but challenge was sent");
               this.disconnect(Message.translation("client.general.disconnect.serverConfigError"));
            }
         } else {
            LOGGER.at(Level.WARNING).log("Received empty password hash from %s", this.getChannel().formatRemoteAddress());
            this.disconnect(Message.translation("client.general.disconnect.invalidPasswordResponse"));
         }
      } else {
         LOGGER.at(Level.WARNING).log("Received unexpected PasswordResponse from %s - no password required", this.getChannel().formatRemoteAddress());
         this.disconnect(Message.translation("client.general.disconnect.protocol.unexpectedPasswordResponse"));
      }
   }

   class="kw">private class="kw">static byte[] generateChallenge() {
      byte[] var0 = new byte[32];
      new SecureRandom().nextBytes(var0);
      class="kw">return var0;
   }

   class="kw">private void proceedToSetup() {
      this.auth = this.pendingAuth;
      LOGGER.at(Level.INFO)
         .log("Connection complete for %s (%s) (SNI: %s), transitioning to setup", this.auth.getUsername(), this.auth.getUuid(), this.getSniHostname());
      this.getChannel().setChannelHandler(this.setupHandlerSupplier.create(this.getChannel(), this.protocolVersion, this.language, this.auth));
   }

   @Nullable
   class="kw">private class="kw">static byte[] computePasswordHash(byte[] var0, String var1) {
      try {
         MessageDigest var2 = MessageDigest.getInstance("SHA-256");
         var2.update(var0);
         var2.update(var1.getBytes(StandardCharsets.UTF_8));
         class="kw">return var2.digest();
      } catch (NoSuchAlgorithmException var3) {
         class="kw">return null;
      }
   }

   @FunctionalInterface
   class="kw">public class="kw">interface SetupHandlerSupplier {
      PacketHandler create(ChannelConnection var1, ProtocolVersion var2, String var3, PlayerAuthentication var4);
   }
}