diff --git a/api/src/main/java/net/md_5/bungee/api/connection/PendingConnection.java b/api/src/main/java/net/md_5/bungee/api/connection/PendingConnection.java index cc511ef..28ac38c 100644 --- a/api/src/main/java/net/md_5/bungee/api/connection/PendingConnection.java +++ b/api/src/main/java/net/md_5/bungee/api/connection/PendingConnection.java @@ -70,12 +70,4 @@ public interface PendingConnection extends Connection * Set this connection's online mode. */ void setOnlineMode(boolean onlineMode); - - /** - * Check if the client is using the older unsupported Minecraft protocol - * used by Minecraft clients older than 1.7. - * - * @return Whether the client is using a legacy client. - */ - boolean isLegacy(); } diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index 48f56b3..238ab60 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -58,6 +58,7 @@ <archive> <manifestEntries> <Main-Class>net.md_5.bungee.Bootstrap</Main-Class> + <Class-Path>Launcher.jar</Class-Path> <Implementation-Version>${describe}</Implementation-Version> <Specification-Version>${maven.build.timestamp}</Specification-Version> </manifestEntries> diff --git a/bootstrap/src/main/java/net/md_5/bungee/Bootstrap.java b/bootstrap/src/main/java/net/md_5/bungee/Bootstrap.java index b7cb81e..6be2273 100644 --- a/bootstrap/src/main/java/net/md_5/bungee/Bootstrap.java +++ b/bootstrap/src/main/java/net/md_5/bungee/Bootstrap.java @@ -5,9 +5,9 @@ public class Bootstrap public static void main(String[] args) throws Exception { - if ( Float.parseFloat( System.getProperty( "java.class.version" ) ) < 51.0 ) + if ( Float.parseFloat( System.getProperty( "java.class.version" ) ) < 52.0 ) { - System.err.println( "*** ERROR *** BungeeCord requires Java 7 or above to function! Please download and install it!" ); + System.err.println( "*** ERROR *** BungeeCord requires Java 8 or above to function! Please download and install it!" ); System.out.println( "You can check your Java version with the command: java -version" ); return; } diff --git a/pom.xml b/pom.xml index 1376c1a..c3821d8 100644 --- a/pom.xml +++ b/pom.xml @@ -66,8 +66,8 @@ <properties> <build.number>unknown</build.number> <netty.version>4.0.31.Final</netty.version> - <maven.compiler.source>1.7</maven.compiler.source> - <maven.compiler.target>1.7</maven.compiler.target> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> @@ -96,6 +96,13 @@ <version>1.14.8</version> <scope>provided</scope> </dependency> + <dependency> + <groupId>launcher</groupId> + <artifactId>clientside</artifactId> + <version>12.0+</version> + <scope>system</scope> + <systemPath>/full/path/to/Launcher.jar</systemPath> + </dependency> </dependencies> <build> @@ -117,31 +124,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>animal-sniffer-maven-plugin</artifactId> - <version>1.13</version> - <executions> - <execution> - <phase>process-classes</phase> - <goals> - <goal>check</goal> - </goals> - </execution> - </executions> - <configuration> - <ignores> - <ignore>java.lang.ClassLoader</ignore> - <ignore>java.lang.Throwable</ignore> - <ignore>java.util.Locale</ignore> - </ignores> - <signature> - <groupId>org.codehaus.mojo.signature</groupId> - <artifactId>java16</artifactId> - <version>1.1</version> - </signature> - </configuration> - </plugin> <!-- OSS Parent 9 uses 2.7, 2.10+ is broken anyway --> <plugin> <groupId>org.apache.maven.plugins</groupId> diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/AbstractPacketHandler.java b/protocol/src/main/java/net/md_5/bungee/protocol/AbstractPacketHandler.java index d292ecd..327b129 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/AbstractPacketHandler.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/AbstractPacketHandler.java @@ -19,8 +19,6 @@ import net.md_5.bungee.protocol.packet.Kick; import net.md_5.bungee.protocol.packet.Respawn; import net.md_5.bungee.protocol.packet.Handshake; import net.md_5.bungee.protocol.packet.EncryptionResponse; -import net.md_5.bungee.protocol.packet.LegacyHandshake; -import net.md_5.bungee.protocol.packet.LegacyPing; import net.md_5.bungee.protocol.packet.LoginRequest; import net.md_5.bungee.protocol.packet.LoginSuccess; import net.md_5.bungee.protocol.packet.PingPacket; @@ -32,10 +30,6 @@ import net.md_5.bungee.protocol.packet.Title; public abstract class AbstractPacketHandler { - public void handle(LegacyPing ping) throws Exception - { - } - public void handle(TabCompleteResponse tabResponse) throws Exception { } @@ -136,10 +130,6 @@ public abstract class AbstractPacketHandler { } - public void handle(LegacyHandshake legacyHandshake) throws Exception - { - } - public void handle(SetCompression setCompression) throws Exception { } diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/KickStringWriter.java b/protocol/src/main/java/net/md_5/bungee/protocol/KickStringWriter.java deleted file mode 100644 index eda9571..0000000 --- a/protocol/src/main/java/net/md_5/bungee/protocol/KickStringWriter.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.md_5.bungee.protocol; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToByteEncoder; - -public class KickStringWriter extends MessageToByteEncoder<String> -{ - - @Override - protected void encode(ChannelHandlerContext ctx, String msg, ByteBuf out) throws Exception - { - out.writeByte( 0xFF ); - out.writeShort( msg.length() ); - for ( char c : msg.toCharArray() ) - { - out.writeChar( c ); - } - } -} diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/LegacyDecoder.java b/protocol/src/main/java/net/md_5/bungee/protocol/LegacyDecoder.java deleted file mode 100644 index 334a8ea..0000000 --- a/protocol/src/main/java/net/md_5/bungee/protocol/LegacyDecoder.java +++ /dev/null @@ -1,39 +0,0 @@ -package net.md_5.bungee.protocol; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageDecoder; -import java.util.List; -import net.md_5.bungee.protocol.packet.LegacyHandshake; -import net.md_5.bungee.protocol.packet.LegacyPing; - -public class LegacyDecoder extends ByteToMessageDecoder -{ - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception - { - if ( !in.isReadable() ) - { - return; - } - - in.markReaderIndex(); - short packetID = in.readUnsignedByte(); - - if ( packetID == 0xFE ) - { - out.add( new PacketWrapper( new LegacyPing( in.isReadable() && in.readUnsignedByte() == 0x01 ), Unpooled.EMPTY_BUFFER ) ); - return; - } else if ( packetID == 0x02 && in.isReadable() ) - { - in.skipBytes( in.readableBytes() ); - out.add( new PacketWrapper( new LegacyHandshake(), Unpooled.EMPTY_BUFFER ) ); - return; - } - - in.resetReaderIndex(); - ctx.pipeline().remove( this ); - } -} diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/LegacyHandshake.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/LegacyHandshake.java deleted file mode 100644 index 50d7381..0000000 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/LegacyHandshake.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.md_5.bungee.protocol.packet; - -import io.netty.buffer.ByteBuf; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; -import net.md_5.bungee.protocol.AbstractPacketHandler; -import net.md_5.bungee.protocol.DefinedPacket; - -@Data -@NoArgsConstructor -@EqualsAndHashCode(callSuper = false) -public class LegacyHandshake extends DefinedPacket -{ - - @Override - public void read(ByteBuf buf) - { - throw new UnsupportedOperationException( "Not supported yet." ); - } - - @Override - public void write(ByteBuf buf) - { - throw new UnsupportedOperationException( "Not supported yet." ); - } - - @Override - public void handle(AbstractPacketHandler handler) throws Exception - { - handler.handle( this ); - } -} diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/LegacyPing.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/LegacyPing.java deleted file mode 100644 index b0f9be2..0000000 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/LegacyPing.java +++ /dev/null @@ -1,36 +0,0 @@ -package net.md_5.bungee.protocol.packet; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.RequiredArgsConstructor; - -import io.netty.buffer.ByteBuf; -import net.md_5.bungee.protocol.AbstractPacketHandler; -import net.md_5.bungee.protocol.DefinedPacket; - -@Data -@RequiredArgsConstructor -@EqualsAndHashCode(callSuper = false) -public class LegacyPing extends DefinedPacket -{ - - private final boolean v1_5; - - @Override - public void read(ByteBuf buf) - { - throw new UnsupportedOperationException( "Not supported yet." ); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public void write(ByteBuf buf) - { - throw new UnsupportedOperationException( "Not supported yet." ); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public void handle(AbstractPacketHandler handler) throws Exception - { - handler.handle( this ); - } -} diff --git a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java index c13d2e6..b1a380b 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java @@ -51,14 +51,15 @@ import net.md_5.bungee.api.event.PreLoginEvent; import net.md_5.bungee.jni.cipher.BungeeCipher; import net.md_5.bungee.protocol.Protocol; import net.md_5.bungee.protocol.ProtocolConstants; -import net.md_5.bungee.protocol.packet.LegacyHandshake; -import net.md_5.bungee.protocol.packet.LegacyPing; import net.md_5.bungee.protocol.packet.LoginRequest; import net.md_5.bungee.protocol.packet.LoginSuccess; import net.md_5.bungee.protocol.packet.PingPacket; import net.md_5.bungee.protocol.packet.StatusRequest; import net.md_5.bungee.protocol.packet.StatusResponse; +import launcher.client.PlayerProfile; +import launcher.request.auth.CheckServerRequest; + @RequiredArgsConstructor public class InitialHandler extends PacketHandler implements PendingConnection { @@ -94,8 +95,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection @Getter private LoginResult loginProfile; @Getter - private boolean legacy; - @Getter private String extraDataInHandshake = ""; private enum State @@ -127,60 +126,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection } } - @Override - public void handle(LegacyHandshake legacyHandshake) throws Exception - { - this.legacy = true; - ch.getHandle().writeAndFlush( bungee.getTranslation( "outdated_client" ) ); - ch.close(); - } - - @Override - public void handle(LegacyPing ping) throws Exception - { - this.legacy = true; - final boolean v1_5 = ping.isV1_5(); - - ServerPing legacy = new ServerPing( new ServerPing.Protocol( bungee.getName() + " " + bungee.getGameVersion(), bungee.getProtocolVersion() ), - new ServerPing.Players( listener.getMaxPlayers(), bungee.getOnlineCount(), null ), listener.getMotd(), (Favicon) null ); - - Callback<ProxyPingEvent> callback = new Callback<ProxyPingEvent>() - { - @Override - public void done(ProxyPingEvent result, Throwable error) - { - if ( ch.isClosed() ) - { - return; - } - - ServerPing legacy = result.getResponse(); - String kickMessage; - - if ( v1_5 ) - { - kickMessage = ChatColor.DARK_BLUE - + "\00" + 127 - + '\00' + legacy.getVersion().getName() - + '\00' + getFirstLine( legacy.getDescription() ) - + '\00' + legacy.getPlayers().getOnline() - + '\00' + legacy.getPlayers().getMax(); - } else - { - // Clients <= 1.3 don't support colored motds because the color char is used as delimiter - kickMessage = ChatColor.stripColor( getFirstLine( legacy.getDescription() ) ) - + '\u00a7' + legacy.getPlayers().getOnline() - + '\u00a7' + legacy.getPlayers().getMax(); - } - - ch.getHandle().writeAndFlush( kickMessage ); - ch.close(); - } - }; - - bungee.getPluginManager().callEvent( new ProxyPingEvent( this, legacy, callback ) ); - } - private static String getFirstLine(String str) { int pos = str.indexOf( '\n' ); @@ -383,35 +328,26 @@ public class InitialHandler extends PacketHandler implements PendingConnection { sha.update( bit ); } - String encodedHash = URLEncoder.encode( new BigInteger( sha.digest() ).toString( 16 ), "UTF-8" ); - - String authURL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" + encName + "&serverId=" + encodedHash; - Callback<String> handler = new Callback<String>() - { - @Override - public void done(String result, Throwable error) - { - if ( error == null ) - { - LoginResult obj = BungeeCord.getInstance().gson.fromJson( result, LoginResult.class ); - if ( obj != null ) - { - loginProfile = obj; - uniqueId = Util.getUUID( obj.getId() ); - finish(); - return; - } - disconnect( "Not authenticated with Minecraft.net" ); - } else - { - disconnect( bungee.getTranslation( "mojang_fail" ) ); - bungee.getLogger().log( Level.SEVERE, "Error authenticating " + getName() + " with minecraft.net", error ); + final String username = InitialHandler.this.getName(); + final String serverID = new BigInteger(sha.digest()).toString(16); + ch.getHandle().eventLoop().execute(() -> { + try { + PlayerProfile pp = new CheckServerRequest(username, serverID).request(); + if(pp == null) { // Invalid username or serverID + disconnect("Bad Login (Serverside)"); + return; } - } - }; - HttpClient.get( authURL, ch.getHandle().eventLoop(), handler ); + // Successful login + loginProfile = new LoginResult(pp); + uniqueId = pp.uuid; + finish(); + } catch(Exception e) { + disconnect("Authentication failed"); + bungee.getLogger().log(Level.SEVERE, "Error authenticating " + username + " with Launcher", e); + } + }); } private void finish() diff --git a/proxy/src/main/java/net/md_5/bungee/connection/LoginResult.java b/proxy/src/main/java/net/md_5/bungee/connection/LoginResult.java index 9311ef7..a281e3f 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/LoginResult.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/LoginResult.java @@ -3,6 +3,17 @@ package net.md_5.bungee.connection; import lombok.AllArgsConstructor; import lombok.Data; +import java.net.URL; +import java.io.IOException; +import java.io.FileNotFoundException; +import java.net.UnknownHostException; +import java.util.List; +import java.util.LinkedList; +import launcher.client.PlayerProfile; +import launcher.client.ClientLauncher; +import launcher.helper.LogHelper; +import launcher.helper.SecurityHelper; + @Data @AllArgsConstructor public class LoginResult @@ -11,6 +22,38 @@ public class LoginResult private String id; private Property[] properties; + public LoginResult(PlayerProfile pp) { + id = ClientLauncher.toHash(pp.uuid); + List<Property> properitesList = new LinkedList<>(); + String skinHash = hash(pp.skinURL); + if(skinHash != null) { + properitesList.add(new Property(ClientLauncher.SKIN_URL_PROPERTY, pp.skinURL, "")); + properitesList.add(new Property("l_skinHash", skinHash, "")); + } + String cloakHash = hash(pp.cloakURL); + if(cloakHash != null) { + properitesList.add(new Property(ClientLauncher.CLOAK_URL_PROPERTY, pp.cloakURL, "")); + properitesList.add(new Property("l_cloakHash", cloakHash, "")); + } + properties = properitesList.toArray(new Property[properitesList.size()]); + } + + private static String hash(String url) { + if (url == null) { + return null; + } + + // Try get digest of the texture + try { + return SecurityHelper.toHex(SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256, new URL(url))); + } catch (FileNotFoundException e) { + return null; // Just didn't has texture + } catch (IOException e) { + LogHelper.error("Can't hash texture: %s, %s", url, e.toString()); + return null; + } + } + @Data @AllArgsConstructor public static class Property diff --git a/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java b/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java index 13637df..d013304 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java @@ -58,27 +58,6 @@ public class UpstreamBridge extends PacketHandler if ( con.getServer() != null ) { - // Manually remove from everyone's tab list - // since the packet from the server arrives - // too late - // TODO: This should only done with server_unique - // tab list (which is the only one supported - // currently) - PlayerListItem packet = new PlayerListItem(); - packet.setAction( PlayerListItem.Action.REMOVE_PLAYER ); - PlayerListItem.Item item = new PlayerListItem.Item(); - item.setUuid( con.getUniqueId() ); - packet.setItems( new PlayerListItem.Item[] - { - item - } ); - for ( ProxiedPlayer player : con.getServer().getInfo().getPlayers() ) - { - if ( player.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_8 ) - { - player.unsafe().sendPacket( packet ); - } - } con.getServer().disconnect( "Quitting" ); } } diff --git a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java index 7b705fc..c549187 100644 --- a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java +++ b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java @@ -30,8 +30,6 @@ import net.md_5.bungee.Util; import net.md_5.bungee.connection.InitialHandler; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.config.ListenerInfo; -import net.md_5.bungee.protocol.KickStringWriter; -import net.md_5.bungee.protocol.LegacyDecoder; import net.md_5.bungee.protocol.MinecraftDecoder; import net.md_5.bungee.protocol.MinecraftEncoder; import net.md_5.bungee.protocol.Protocol; @@ -57,10 +55,8 @@ public class PipelineUtils } BASE.initChannel( ch ); - ch.pipeline().addBefore( FRAME_DECODER, LEGACY_DECODER, new LegacyDecoder() ); ch.pipeline().addAfter( FRAME_DECODER, PACKET_DECODER, new MinecraftDecoder( Protocol.HANDSHAKE, true, ProxyServer.getInstance().getProtocolVersion() ) ); ch.pipeline().addAfter( FRAME_PREPENDER, PACKET_ENCODER, new MinecraftEncoder( Protocol.HANDSHAKE, true, ProxyServer.getInstance().getProtocolVersion() ) ); - ch.pipeline().addBefore( FRAME_PREPENDER, LEGACY_KICKER, new KickStringWriter() ); ch.pipeline().get( HandlerBoss.class ).setHandler( new InitialHandler( ProxyServer.getInstance(), ch.attr( LISTENER ).get() ) ); } }; @@ -74,8 +70,6 @@ public class PipelineUtils public static final String DECRYPT_HANDLER = "decrypt"; public static final String FRAME_DECODER = "frame-decoder"; public static final String FRAME_PREPENDER = "frame-prepender"; - public static final String LEGACY_DECODER = "legacy-decoder"; - public static final String LEGACY_KICKER = "legacy-kick"; private static boolean epoll;