package main.com.pyratron.pugmatt.bedrockconnect.listeners; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.JsonNodeType; import com.nukkitx.math.vector.Vector2f; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.CompoundTagBuilder; import com.nukkitx.nbt.NbtUtils; import com.nukkitx.nbt.stream.NBTOutputStream; import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.network.util.Preconditions; import com.nukkitx.protocol.bedrock.BedrockClientSession; import com.nukkitx.protocol.bedrock.data.GamePublishSetting; import com.nukkitx.protocol.bedrock.packet.*; import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.JWSObject; import com.nimbusds.jose.crypto.factories.DefaultJWSVerifierFactory; import com.nukkitx.protocol.bedrock.BedrockServerSession; import com.nukkitx.protocol.bedrock.handler.BedrockPacketHandler; import com.nukkitx.protocol.bedrock.packet.LoginPacket; import com.nukkitx.protocol.bedrock.util.EncryptionUtils; import main.com.pyratron.pugmatt.bedrockconnect.BedrockConnect; import main.com.pyratron.pugmatt.bedrockconnect.Server; import main.com.pyratron.pugmatt.bedrockconnect.gui.UIComponents; import main.com.pyratron.pugmatt.bedrockconnect.gui.UIForms; import net.minidev.json.JSONObject; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.interfaces.ECPublicKey; import java.util.ArrayList; import java.util.List; // Heavily referenced from https://github.com/NukkitX/ProxyPass/blob/master/src/main/java/com/nukkitx/proxypass/network/bedrock/session/UpstreamPacketHandler.java public class PacketHandler implements BedrockPacketHandler { private Server server; private BedrockServerSession session; private String name; private String uuid; private JSONObject extraData; private boolean print = false; private static final CompoundTag EMPTY_TAG = CompoundTagBuilder.builder().buildRootTag(); private static final byte[] EMPTY_LEVEL_CHUNK_DATA; static { try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { outputStream.write(new byte[258]); // Biomes + Border Size + Extra Data Size try (NBTOutputStream stream = NbtUtils.createNetworkWriter(outputStream)) { stream.write(EMPTY_TAG); } EMPTY_LEVEL_CHUNK_DATA = outputStream.toByteArray(); }catch (IOException e) { throw new AssertionError("Unable to generate empty level chunk data"); } } @Override public boolean handle(AdventureSettingsPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(AnimatePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(BlockEntityDataPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(BlockPickRequestPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(BookEditPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ClientToServerHandshakePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(CommandBlockUpdatePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(CommandRequestPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ContainerClosePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(CraftingEventPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(EntityEventPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(EntityFallPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(EntityPickRequestPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(EventPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(InteractPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(InventoryContentPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(InventorySlotPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(InventoryTransactionPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ItemFrameDropItemPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(LabTablePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(LecternUpdatePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(LevelSoundEventPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(MapInfoRequestPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(MobArmorEquipmentPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(MobEquipmentPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(MoveEntityAbsolutePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(MovePlayerPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(NetworkStackLatencyPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(PhotoTransferPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(PlayerActionPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(PlayerHotbarPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(PlayerInputPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(PlayerSkinPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(PurchaseReceiptPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(RequestChunkRadiusPacket packet) { if(print) System.out.println(packet.toString()); ChunkRadiusUpdatedPacket chunkRadiusUpdatePacket = new ChunkRadiusUpdatedPacket(); chunkRadiusUpdatePacket.setRadius(packet.getRadius()); session.sendPacketImmediately(chunkRadiusUpdatePacket); PlayStatusPacket playStatus = new PlayStatusPacket(); playStatus.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN); session.sendPacket(playStatus); /* Vector3f pos = Vector3f.ZERO; int chunkX = pos.getFloorX() >> 4; int chunkZ = pos.getFloorX() >> 4; for (int x = -3; x < 3; x++) { for (int z = -3; z < 3; z++) { LevelChunkPacket data2 = new LevelChunkPacket(); data2.setChunkX(chunkX + x); data2.setChunkZ(chunkZ + z); data2.setSubChunksLength(0); data2.setData(EMPTY_LEVEL_CHUNK_DATA); session.sendPacket(data2); } } System.out.println("test"); PlayStatusPacket playStatus = new PlayStatusPacket(); playStatus.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN); session.sendPacket(playStatus); System.out.println("test2"); */ return false; } @Override public boolean handle(RiderJumpPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ServerSettingsRequestPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetDefaultGameTypePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetPlayerGameTypePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SubClientLoginPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(TextPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(AddBehaviorTreePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(AddEntityPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(AddHangingEntityPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(AddItemEntityPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(AddPaintingPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(AddPlayerPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(AvailableCommandsPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(BlockEventPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(BossEventPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(CameraPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ChangeDimensionPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ChunkRadiusUpdatedPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ClientboundMapItemDataPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(CommandOutputPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ContainerOpenPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ContainerSetDataPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(CraftingDataPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ExplodePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(GameRulesChangedPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(GuiDataPickItemPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(HurtArmorPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(AutomationClientConnectPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(LevelEventPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(MapCreateLockedCopyPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(MobEffectPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ModalFormRequestPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(MoveEntityDeltaPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(NpcRequestPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(OnScreenTextureAnimationPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(PlayerListPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(PlaySoundPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(PlayStatusPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(RemoveEntityPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(RemoveObjectivePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ResourcePackChunkDataPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ResourcePackDataInfoPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ResourcePacksInfoPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ResourcePackStackPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(RespawnPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ScriptCustomEventPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ServerSettingsResponsePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ServerToClientHandshakePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetCommandsEnabledPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetDifficultyPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetDisplayObjectivePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetEntityDataPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetEntityLinkPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetEntityMotionPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetHealthPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetLastHurtByPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetScoreboardIdentityPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetScorePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetSpawnPositionPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetTimePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SetTitlePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ShowCreditsPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ShowProfilePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ShowStoreOfferPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SimpleEventPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SpawnExperienceOrbPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(StartGamePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(StopSoundPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(StructureBlockUpdatePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(TakeItemEntityPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(TransferPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(UpdateAttributesPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(UpdateBlockPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(UpdateBlockSyncedPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(UpdateEquipPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(UpdateSoftEnumPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(UpdateTradePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(AvailableEntityIdentifiersPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(BiomeDefinitionListPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(LevelSoundEvent2Packet packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(NetworkChunkPublisherUpdatePacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(SpawnParticleEffectPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(VideoStreamConnectPacket packet) { if(print) System.out.println(packet.toString()); return false; } @Override public boolean handle(ResourcePackChunkRequestPacket packet) { if(print) System.out.println(packet.toString()); return true; } @Override public boolean handle(ModalFormResponsePacket packet) { if(print) System.out.println(packet.toString()); switch (packet.getFormId()) { case UIForms.MAIN: if(UIForms.currentForm == UIForms.MAIN) { // If exiting main window if (packet.getFormData().contains("null")) { session.disconnect("Exiting Server List"); } else { // If selecting button int chosen = Integer.parseInt(packet.getFormData().replaceAll("\\s+","")); if (chosen == 0) { // Add Server session.sendPacketImmediately(UIForms.createDirectConnect()); } else if (chosen == 1) { // Remove Server session.sendPacketImmediately(UIForms.createRemoveServer(server.getPlayer(uuid).getServerList())); } else { // Choosing Server // If server chosen is a featued server if(chosen-2 > server.getPlayer(uuid).getServerList().size()-1) { int featuredServer = (chosen - 2) - (server.getPlayer(uuid).getServerList().size() - 1); switch (featuredServer) { case 1: // Hive transfer("54.39.75.136", 19132); break; case 2: // Mineplex transfer("108.178.12.125", 19132); break; case 3: // Cubecraft transfer("213.32.11.233", 19132); break; case 4: // Lifeboat transfer("63.143.40.66", 19132); break; case 5: // Mineville transfer("52.234.131.7", 19132); break; } } else { // If server chosen is not a featured server String address = server.getPlayer(uuid).getServerList().get(chosen-2); if (address.split(":").length > 1) { String ip = address.split(":")[0]; String port = address.split(":")[1]; try { transfer(ip, Integer.parseInt(port)); } catch (Exception e) { session.sendPacketImmediately(UIForms.createError("Error connecting to server. Invalid address.")); } } else { session.sendPacketImmediately(UIForms.createError("Invalid server address")); } } } } } break; case UIForms.DIRECT_CONNECT: try { if(packet.getFormData().contains("null")) session.sendPacketImmediately(UIForms.createMain(server.getPlayer(uuid).getServerList())); else { ArrayList<String> data = UIComponents.getFormData(packet.getFormData()); if(data.size() > 1) { // Remove any whitespace data.set(0, data.get(0).replaceAll("\\s","")); data.set(1, data.get(1).replaceAll("\\s","")); if(data.get(0).length() >= 253) session.sendPacketImmediately(UIForms.createError("Address is too large. (Must be less than 253)")); else if(data.get(1).length() >= 10) session.sendPacketImmediately(UIForms.createError("Port is too large. (Must be less than 10)")); else if (!data.get(0).matches("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$") && !data.get(0).matches("^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}$")) session.sendPacketImmediately(UIForms.createError("Enter a valid address. (E.g. play.example.net, 172.16.254.1)")); else if (!data.get(1).matches("[0-9]+")) session.sendPacketImmediately(UIForms.createError("Enter a valid port that contains only numbers")); else { boolean addServer = Boolean.parseBoolean(data.get(2)); if (addServer) { List<String> serverList = server.getPlayer(uuid).getServerList(); if (serverList.size() >= server.getPlayer(uuid).getServerLimit()) session.sendPacketImmediately(UIForms.createError("You have hit your serverlist limit of " + server.getPlayer(uuid).getServerLimit() + " servers. Remove some to add more.")); else { serverList.add(data.get(0) + ":" + data.get(1)); server.getPlayer(uuid).setServerList(serverList); transfer(data.get(0).replace(" ", ""), Integer.parseInt(data.get(1))); } } else { TransferPacket tp = new TransferPacket(); tp.setAddress(data.get(0).replace(" ", "")); tp.setPort(Integer.parseInt(data.get(1))); session.sendPacketImmediately(tp); } } } } } catch(Exception e) { session.sendPacketImmediately(UIForms.createError("Please enter a valid IP/Address and port that contains only numbers.")); } break; case UIForms.REMOVE_SERVER: try { if(packet.getFormData().contains("null")) session.sendPacketImmediately(UIForms.createMain(server.getPlayer(uuid).getServerList())); else { ArrayList<String> data = UIComponents.getFormData(packet.getFormData()); int chosen = Integer.parseInt(data.get(0)); List<String> serverList = server.getPlayer(uuid).getServerList(); serverList.remove(chosen); server.getPlayer(uuid).setServerList(serverList); session.sendPacketImmediately(UIForms.createMain(serverList)); } } catch(Exception e) { session.sendPacketImmediately(UIForms.createError("Invalid server to remove")); } break; case UIForms.ERROR: session.sendPacketImmediately(UIForms.createMain(server.getPlayer(uuid).getServerList())); break; } return false; } public void transfer(String ip, int port) { TransferPacket tp = new TransferPacket(); tp.setAddress(ip); tp.setPort(port); session.sendPacketImmediately(tp); } @Override public boolean handle(SetLocalPlayerAsInitializedPacket packet) { if(print) System.out.println(packet.toString()); session.sendPacketImmediately(UIForms.createMain(server.getPlayer(uuid).getServerList())); return false; } public PacketHandler(BedrockServerSession session, Server server) { this.session = session; this.server = server; session.addDisconnectHandler((DisconnectReason) -> disconnect()); } public void disconnect() { System.out.println(name + " disconnected"); server.removePlayer(server.getPlayer(uuid)); } private static boolean validateChainData(JsonNode data) throws Exception { ECPublicKey lastKey = null; boolean validChain = false; for (JsonNode node : data) { JWSObject jwt = JWSObject.parse(node.asText()); if (!validChain) { validChain = verifyJwt(jwt, EncryptionUtils.getMojangPublicKey()); } if (lastKey != null) { verifyJwt(jwt, lastKey); } JsonNode payloadNode = Server.JSON_MAPPER.readTree(jwt.getPayload().toString()); JsonNode ipkNode = payloadNode.get("identityPublicKey"); Preconditions.checkState(ipkNode != null && ipkNode.getNodeType() == JsonNodeType.STRING, "identityPublicKey node is missing in chain"); lastKey = EncryptionUtils.generateKey(ipkNode.asText()); } return validChain; } private static boolean verifyJwt(JWSObject jwt, ECPublicKey key) throws JOSEException { return jwt.verify(new DefaultJWSVerifierFactory().createJWSVerifier(jwt.getHeader(), key)); } @Override public boolean handle(DisconnectPacket packet) { return false; } @Override public boolean handle(ResourcePackClientResponsePacket packet) { if(print) System.out.println(packet.toString()); switch (packet.getStatus()) { case COMPLETED: BedrockConnect.data.userExists(uuid, name, session); break; case HAVE_ALL_PACKS: ResourcePackStackPacket rs = new ResourcePackStackPacket(); //rs.setExperimental(false); rs.setForcedToAccept(false); rs.setGameVersion(Server.codec.getMinecraftVersion()); session.sendPacket(rs); break; default: session.disconnect("disconnectionScreen.resourcePack"); break; } return true; } @Override public boolean handle(LoginPacket packet) { if(print) System.out.println(packet.toString()); int protocolVersion = packet.getProtocolVersion(); if (protocolVersion != server.getProtocol()) { PlayStatusPacket status = new PlayStatusPacket(); if (protocolVersion > server.getProtocol()) { status.setStatus(PlayStatusPacket.Status.FAILED_SERVER); } else { status.setStatus(PlayStatusPacket.Status.FAILED_CLIENT); } session.sendPacket(status); } session.setPacketCodec(server.getCodec()); JsonNode certData; try { certData = Server.JSON_MAPPER.readTree(packet.getChainData().toByteArray()); } catch (IOException e) { throw new RuntimeException("Certificate JSON can not be read."); } JsonNode certChainData = certData.get("chain"); if (certChainData.getNodeType() != JsonNodeType.ARRAY) { throw new RuntimeException("Certificate data is not valid"); } boolean validChain; try { validChain = validateChainData(certChainData); JWSObject jwt = JWSObject.parse(certChainData.get(certChainData.size() - 1).asText()); JsonNode payload = Server.JSON_MAPPER.readTree(jwt.getPayload().toBytes()); if (payload.get("extraData").getNodeType() != JsonNodeType.OBJECT) { throw new RuntimeException("AuthData was not found!"); } extraData = (JSONObject) jwt.getPayload().toJSONObject().get("extraData"); if (payload.get("identityPublicKey").getNodeType() != JsonNodeType.STRING) { throw new RuntimeException("Identity Public Key was not found!"); } ECPublicKey identityPublicKey = EncryptionUtils.generateKey(payload.get("identityPublicKey").textValue()); JWSObject clientJwt = JWSObject.parse(packet.getSkinData().toString()); verifyJwt(clientJwt, identityPublicKey); System.out.println("Made it through login - " + "User: " + extraData.getAsString("displayName") + " (" + extraData.getAsString("identity") + ")"); name = extraData.getAsString("displayName"); uuid = extraData.getAsString("identity"); PlayStatusPacket status = new PlayStatusPacket(); status.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS); session.sendPacket(status); SetEntityMotionPacket motion = new SetEntityMotionPacket(); motion.setRuntimeEntityId(1); motion.setMotion(Vector3f.ZERO); session.sendPacket(motion); ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket(); resourcePacksInfo.setForcedToAccept(false); resourcePacksInfo.setScriptingEnabled(false); session.sendPacket(resourcePacksInfo); } catch (Exception e) { session.disconnect("disconnectionScreen.internalError.cantConnect"); throw new RuntimeException("Unable to complete login", e); } return true; } }