From df6836e12b76218530c4b34ecf58670053b08f71 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Wed, 24 Jul 2019 01:29:54 -0500 Subject: [PATCH] Add authentication/online mode support --- README.md | 2 +- .../geysermc/api/window/CustomFormWindow.java | 2 +- common/pom.xml | 6 - .../network/UpstreamPacketHandler.java | 48 ++++-- .../network/session/GeyserSession.java | 142 +++++++++++++++--- .../network/translators/TranslatorsInit.java | 60 -------- 6 files changed, 156 insertions(+), 104 deletions(-) diff --git a/README.md b/README.md index 619a0a78b..a23afe99e 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ https://discord.gg/mRjbCsS ## What's Completed - [x] Server recognized in server list - [x] Join detection from remote -- [ ] Online mode/auth support +- [x] Online mode/auth support - [x] Chat/command support - [ ] Inventory support - [ ] Movement support diff --git a/api/src/main/java/org/geysermc/api/window/CustomFormWindow.java b/api/src/main/java/org/geysermc/api/window/CustomFormWindow.java index afc6d72c0..66efd850e 100644 --- a/api/src/main/java/org/geysermc/api/window/CustomFormWindow.java +++ b/api/src/main/java/org/geysermc/api/window/CustomFormWindow.java @@ -92,7 +92,7 @@ public class CustomFormWindow extends FormWindow { } public void setResponse(String data) { - if (data == null || data.equalsIgnoreCase("null")) { + if (data == null || data.equalsIgnoreCase("null") || data.isEmpty()) { closed = true; return; } diff --git a/common/pom.xml b/common/pom.xml index c88332601..6a0a6ff04 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -54,11 +54,5 @@ 3.3.0 compile - - org.apache.commons - commons-lang3 - 3.7 - compile - \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java index 886f86fa5..09b737bcb 100644 --- a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java @@ -35,7 +35,12 @@ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; import net.minidev.json.JSONValue; import org.geysermc.api.events.player.PlayerFormResponseEvent; +import org.geysermc.api.window.CustomFormBuilder; +import org.geysermc.api.window.CustomFormWindow; import org.geysermc.api.window.FormWindow; +import org.geysermc.api.window.component.InputComponent; +import org.geysermc.api.window.component.LabelComponent; +import org.geysermc.api.window.response.CustomFormResponse; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.auth.BedrockAuthData; @@ -86,18 +91,6 @@ public class UpstreamPacketHandler implements BedrockPacketHandler { ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket(); session.getUpstream().sendPacketImmediately(resourcePacksInfo); - - // TODO: Implement this - /** - CustomFormWindow window = new CustomFormBuilder("Login") - .addComponent(new LabelComponent("Minecraft: Java Edition account authentication.")) - .addComponent(new LabelComponent("Enter the credentials for your Minecraft: Java Edition account below.")) - .addComponent(new InputComponent("Email/Username", "account@geysermc.org", "")) - .addComponent(new InputComponent("Password", "123456", "")) - .build(); - - session.sendForm(window, 1); - */ return true; } @@ -107,7 +100,7 @@ public class UpstreamPacketHandler implements BedrockPacketHandler { switch (textPacket.getStatus()) { case COMPLETED: session.connect(connector.getRemoteServer()); - connector.getLogger().info("Player connected with " + session.getAuthenticationData().getName()); + connector.getLogger().info("Player connected with username " + session.getAuthenticationData().getName()); break; case HAVE_ALL_PACKS: ResourcePackStackPacket stack = new ResourcePackStackPacket(); @@ -327,8 +320,22 @@ public class UpstreamPacketHandler implements BedrockPacketHandler { FormWindow window = windowCache.getWindows().remove(packet.getFormId()); window.setResponse(packet.getFormData().trim()); - PlayerFormResponseEvent event = new PlayerFormResponseEvent(session, packet.getFormId(), window); - connector.getPluginManager().runEvent(event); + if (session.isLoggedIn()) { + PlayerFormResponseEvent event = new PlayerFormResponseEvent(session, packet.getFormId(), window); + connector.getPluginManager().runEvent(event); + } else { + if (window instanceof CustomFormWindow) { + CustomFormWindow customFormWindow = (CustomFormWindow) window; + if (!customFormWindow.getTitle().equals("Login")) + return false; + + CustomFormResponse response = (CustomFormResponse) customFormWindow.getResponse(); + session.authenticate(response.getInputResponses().get(2), response.getInputResponses().get(3)); + + // Clear windows so authentication data isn't accidentally cached + windowCache.getWindows().clear(); + } + } return true; } @@ -341,6 +348,17 @@ public class UpstreamPacketHandler implements BedrockPacketHandler { @Override public boolean handle(MovePlayerPacket packet) { connector.getLogger().debug("Handled packet: " + packet.getClass().getSimpleName()); + if (!session.isLoggedIn()) { + CustomFormWindow window = new CustomFormBuilder("Login") + .addComponent(new LabelComponent("Minecraft: Java Edition account authentication.")) + .addComponent(new LabelComponent("Enter the credentials for your Minecraft: Java Edition account below.")) + .addComponent(new InputComponent("Email/Username", "account@geysermc.org", "")) + .addComponent(new InputComponent("Password", "123456", "")) + .build(); + + session.sendForm(window, 1); + return true; + } return false; } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 2fa274765..8cf5ced5d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -25,6 +25,10 @@ package org.geysermc.connector.network.session; +import com.flowpowered.math.vector.Vector2f; +import com.flowpowered.math.vector.Vector3f; +import com.flowpowered.math.vector.Vector3i; +import com.github.steveice10.mc.auth.exception.request.RequestException; import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.github.steveice10.packetlib.Client; import com.github.steveice10.packetlib.event.session.ConnectedEvent; @@ -35,6 +39,10 @@ import com.github.steveice10.packetlib.tcp.TcpSessionFactory; import com.nukkitx.network.util.DisconnectReason; import com.nukkitx.protocol.PlayerSession; import com.nukkitx.protocol.bedrock.BedrockServerSession; +import com.nukkitx.protocol.bedrock.data.GamePublishSetting; +import com.nukkitx.protocol.bedrock.data.GameRule; +import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket; +import com.nukkitx.protocol.bedrock.packet.StartGamePacket; import com.nukkitx.protocol.bedrock.packet.TextPacket; import lombok.Getter; import org.geysermc.api.Player; @@ -44,6 +52,7 @@ import org.geysermc.api.window.FormWindow; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.cache.WindowCache; import org.geysermc.connector.network.translators.Registry; +import org.geysermc.connector.utils.Toolbox; public class GeyserSession implements PlayerSession, Player { @@ -66,6 +75,9 @@ public class GeyserSession implements PlayerSession, Player { @Getter private WindowCache windowCache; + @Getter + private boolean loggedIn; + private boolean closed; public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) { @@ -73,36 +85,70 @@ public class GeyserSession implements PlayerSession, Player { this.upstream = bedrockServerSession; this.windowCache = new WindowCache(this); + + this.loggedIn = false; } public void connect(RemoteServer remoteServer) { - MinecraftProtocol protocol = new MinecraftProtocol(authenticationData.getName()); - downstream = new Client(remoteServer.getAddress(), remoteServer.getPort(), protocol, new TcpSessionFactory()); - downstream.getSession().addListener(new SessionAdapter() { + // This has to be sent first so the player actually joins + startGame(); - @Override - public void connected(ConnectedEvent event) { - connector.getLogger().info(authenticationData.getName() + " has connected to remote java server on address " + remoteServer.getAddress()); - } - - @Override - public void disconnected(DisconnectedEvent event) { - connector.getLogger().info(authenticationData.getName() + " has disconnected from remote java server on address " + remoteServer.getAddress() + " because of " + event.getReason()); - upstream.disconnect(event.getReason()); - } - - @Override - public void packetReceived(PacketReceivedEvent event) { - Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), THIS); - } - }); - - downstream.getSession().connect(); this.remoteServer = remoteServer; + if (!connector.getConfig().getRemote().isOnlineMode()) { + connector.getLogger().info("Attempting to login using offline mode... authentication is disabled."); + authenticate(authenticationData.getName()); + } + } + + public void authenticate(String username) { + authenticate(username, ""); + } + + public void authenticate(String username, String password) { + if (loggedIn) { + connector.getLogger().severe(username + " is already logged in!"); + return; + } + + try { + MinecraftProtocol protocol; + if (password != null && !password.isEmpty()) { + protocol = new MinecraftProtocol(username, password); + } else { + protocol = new MinecraftProtocol(username); + } + + downstream = new Client(remoteServer.getAddress(), remoteServer.getPort(), protocol, new TcpSessionFactory()); + downstream.getSession().addListener(new SessionAdapter() { + + @Override + public void connected(ConnectedEvent event) { + loggedIn = true; + connector.getLogger().info(authenticationData.getName() + " (logged in as: " + protocol.getProfile().getName() + ")" + " has connected to remote java server on address " + remoteServer.getAddress()); + } + + @Override + public void disconnected(DisconnectedEvent event) { + loggedIn = false; + connector.getLogger().info(authenticationData.getName() + " has disconnected from remote java server on address " + remoteServer.getAddress() + " because of " + event.getReason()); + upstream.disconnect(event.getReason()); + } + + @Override + public void packetReceived(PacketReceivedEvent event) { + Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), THIS); + } + }); + + downstream.getSession().connect(); + } catch (RequestException ex) { + ex.printStackTrace(); + } } public void disconnect(String reason) { if (!closed) { + loggedIn = false; downstream.getSession().disconnect(reason); upstream.disconnect(reason); } @@ -164,4 +210,58 @@ public class GeyserSession implements PlayerSession, Player { public void sendForm(FormWindow window) { windowCache.showWindow(window); } + + private void startGame() { + StartGamePacket startGamePacket = new StartGamePacket(); + startGamePacket.setUniqueEntityId(1); // TODO: Cache this value + startGamePacket.setRuntimeEntityId(1); // TODO: Cache this value + startGamePacket.setPlayerGamemode(0); + startGamePacket.setPlayerPosition(new Vector3f(0, 0, 0)); + startGamePacket.setRotation(new Vector2f(1, 1)); + + startGamePacket.setSeed(1111); + startGamePacket.setDimensionId(0); + startGamePacket.setGeneratorId(0); + startGamePacket.setLevelGamemode(0); + startGamePacket.setDifficulty(1); + startGamePacket.setDefaultSpawn(new Vector3i(0, 0, 0)); + startGamePacket.setAcheivementsDisabled(true); + startGamePacket.setTime(0); + startGamePacket.setEduLevel(false); + startGamePacket.setEduFeaturesEnabled(false); + startGamePacket.setRainLevel(0); + startGamePacket.setLightningLevel(0); + startGamePacket.setMultiplayerGame(true); + startGamePacket.setBroadcastingToLan(true); + startGamePacket.getGamerules().add(new GameRule<>("showcoordinates", true)); + startGamePacket.setPlatformBroadcastMode(GamePublishSetting.PUBLIC); + startGamePacket.setXblBroadcastMode(GamePublishSetting.PUBLIC); + startGamePacket.setCommandsEnabled(true); + startGamePacket.setTexturePacksRequired(false); + startGamePacket.setBonusChestEnabled(false); + startGamePacket.setStartingWithMap(false); + startGamePacket.setTrustingPlayers(true); + startGamePacket.setDefaultPlayerPermission(1); + startGamePacket.setServerChunkTickRange(4); + startGamePacket.setBehaviorPackLocked(false); + startGamePacket.setResourcePackLocked(false); + startGamePacket.setFromLockedWorldTemplate(false); + startGamePacket.setUsingMsaGamertagsOnly(false); + startGamePacket.setFromWorldTemplate(false); + startGamePacket.setWorldTemplateOptionLocked(false); + + startGamePacket.setLevelId("oerjhii"); + startGamePacket.setWorldName("world"); + startGamePacket.setPremiumWorldTemplateId("00000000-0000-0000-0000-000000000000"); + startGamePacket.setCurrentTick(0); + startGamePacket.setEnchantmentSeed(0); + startGamePacket.setMultiplayerCorrelationId(""); + startGamePacket.setCachedPalette(Toolbox.CACHED_PALLETE); + startGamePacket.setItemEntries(Toolbox.ITEMS); + upstream.sendPacket(startGamePacket); + + PlayStatusPacket playStatusPacket = new PlayStatusPacket(); + playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN); + upstream.sendPacket(playStatusPacket); + } } \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java index da8a344e6..2794d2bf4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java @@ -25,9 +25,7 @@ package org.geysermc.connector.network.translators; -import com.flowpowered.math.vector.Vector2f; import com.flowpowered.math.vector.Vector3f; -import com.flowpowered.math.vector.Vector3i; import com.github.steveice10.mc.protocol.data.message.TranslationMessage; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerChatPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket; @@ -42,11 +40,8 @@ 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.protocol.bedrock.data.GamePublishSetting; -import com.nukkitx.protocol.bedrock.data.GameRule; import com.nukkitx.protocol.bedrock.packet.*; import org.geysermc.connector.utils.MessageUtils; -import org.geysermc.connector.utils.Toolbox; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -83,60 +78,9 @@ public class TranslatorsInit { private static void addLoginPackets() { Registry.add(ServerJoinGamePacket.class, (packet, session) -> { AdventureSettingsPacket bedrockPacket = new AdventureSettingsPacket(); - bedrockPacket.setUniqueEntityId(packet.getEntityId()); - session.getUpstream().sendPacketImmediately(bedrockPacket); - StartGamePacket startGamePacket = new StartGamePacket(); - startGamePacket.setUniqueEntityId(packet.getEntityId()); - startGamePacket.setRuntimeEntityId(packet.getEntityId()); - startGamePacket.setPlayerGamemode(packet.getGameMode().ordinal()); - startGamePacket.setPlayerPosition(new Vector3f(0, 0, 0)); - startGamePacket.setRotation(new Vector2f(1, 1)); - - startGamePacket.setSeed(1111); - startGamePacket.setDimensionId(0); - startGamePacket.setGeneratorId(0); - startGamePacket.setLevelGamemode(packet.getGameMode().ordinal()); - startGamePacket.setDifficulty(1); - startGamePacket.setDefaultSpawn(new Vector3i(0, 0, 0)); - startGamePacket.setAcheivementsDisabled(true); - startGamePacket.setTime(0); - startGamePacket.setEduLevel(false); - startGamePacket.setEduFeaturesEnabled(false); - startGamePacket.setRainLevel(0); - startGamePacket.setLightningLevel(0); - startGamePacket.setMultiplayerGame(true); - startGamePacket.setBroadcastingToLan(true); - startGamePacket.getGamerules().add(new GameRule<>("showcoordinates", true)); - startGamePacket.setPlatformBroadcastMode(GamePublishSetting.PUBLIC); - startGamePacket.setXblBroadcastMode(GamePublishSetting.PUBLIC); - startGamePacket.setCommandsEnabled(true); - startGamePacket.setTexturePacksRequired(false); - startGamePacket.setBonusChestEnabled(false); - startGamePacket.setStartingWithMap(false); - startGamePacket.setTrustingPlayers(true); - startGamePacket.setDefaultPlayerPermission(1); - startGamePacket.setServerChunkTickRange(4); - startGamePacket.setBehaviorPackLocked(false); - startGamePacket.setResourcePackLocked(false); - startGamePacket.setFromLockedWorldTemplate(false); - startGamePacket.setUsingMsaGamertagsOnly(false); - startGamePacket.setFromWorldTemplate(false); - startGamePacket.setWorldTemplateOptionLocked(false); - - startGamePacket.setLevelId("oerjhii"); - startGamePacket.setWorldName("world"); - startGamePacket.setPremiumWorldTemplateId("00000000-0000-0000-0000-000000000000"); - startGamePacket.setCurrentTick(0); - startGamePacket.setEnchantmentSeed(0); - startGamePacket.setMultiplayerCorrelationId(""); - startGamePacket.setCachedPalette(Toolbox.CACHED_PALLETE); - startGamePacket.setItemEntries(Toolbox.ITEMS); - - session.getUpstream().sendPacket(startGamePacket); - Vector3f pos = new Vector3f(0, 0, 0); int chunkX = pos.getFloorX() >> 4; int chunkZ = pos.getFloorZ() >> 4; @@ -153,10 +97,6 @@ public class TranslatorsInit { } } - - PlayStatusPacket playStatusPacket = new PlayStatusPacket(); - playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN); - session.getUpstream().sendPacket(playStatusPacket); }); }