diff --git a/LaunchServer/runtime/api.js b/LaunchServer/runtime/api.js old mode 120000 new mode 100644 diff --git a/Launcher.stringer b/Launcher.stringer index 5934982..5bdfae7 100644 --- a/Launcher.stringer +++ b/Launcher.stringer @@ -10,14 +10,12 @@ true glob:launcher/** - glob:com/mojang/authlib/** filter glob:launcher/** - glob:com/mojang/authlib/** @@ -27,7 +25,6 @@ false glob:launcher/** - glob:com/mojang/authlib/** diff --git a/Launcher/source-authlib/minecraft/MinecraftProfileTexture.java b/Launcher/source-authlib/minecraft/MinecraftProfileTexture.java index 0d8434c..c3e30a6 100644 --- a/Launcher/source-authlib/minecraft/MinecraftProfileTexture.java +++ b/Launcher/source-authlib/minecraft/MinecraftProfileTexture.java @@ -1,12 +1,21 @@ package com.mojang.authlib.minecraft; +import java.util.Collections; +import java.util.EnumSet; +import java.util.Set; + public final class MinecraftProfileTexture { - public static final int PROFILE_TEXTURE_COUNT = Type.values().length; + public static final Set PROFILE_TEXTURE_TYPES = Collections.unmodifiableSet(EnumSet.allOf(Type.class)); + public static final int PROFILE_TEXTURE_COUNT = PROFILE_TEXTURE_TYPES.size(); // Instance private final String url; private final String hash; + public MinecraftProfileTexture(String url) { + this(url, baseName(url)); + } + public MinecraftProfileTexture(String url, String hash) { this.url = url; this.hash = hash; @@ -32,6 +41,19 @@ return url; } + private static String baseName(String url) { + String name = url.substring(url.lastIndexOf('/') + 1); + + // Remove index + int extensionIndex = name.lastIndexOf('.'); + if (extensionIndex >= 0) { + name = name.substring(0, extensionIndex); + } + + // We're done + return name; + } + public enum Type { SKIN, CAPE, diff --git a/Launcher/source-authlib/yggdrasil/LegacyBridge.java b/Launcher/source-authlib/yggdrasil/LegacyBridge.java index 9d77fd1..30d0d94 100644 --- a/Launcher/source-authlib/yggdrasil/LegacyBridge.java +++ b/Launcher/source-authlib/yggdrasil/LegacyBridge.java @@ -69,8 +69,7 @@ } // Join server - LogHelper.debug("LegacyBridge.joinServer, Username: '%s', Access token: %s, Server ID: %s", - username, accessToken, serverID); + LogHelper.debug("LegacyBridge.joinServer, Username: '%s', Access token: %s, Server ID: %s", username, accessToken, serverID); try { return new JoinServerRequest(username, accessToken, serverID).request() ? "OK" : "Bad Login (Clientside)"; } catch (Exception e) { diff --git a/Launcher/source-authlib/yggdrasil/YggdrasilMinecraftSessionService.java b/Launcher/source-authlib/yggdrasil/YggdrasilMinecraftSessionService.java index 99c3356..281bbe7 100644 --- a/Launcher/source-authlib/yggdrasil/YggdrasilMinecraftSessionService.java +++ b/Launcher/source-authlib/yggdrasil/YggdrasilMinecraftSessionService.java @@ -1,11 +1,15 @@ package com.mojang.authlib.yggdrasil; import java.net.InetAddress; +import java.util.Base64; import java.util.EnumMap; -import java.util.Iterator; import java.util.Map; import java.util.UUID; +import com.eclipsesource.json.Json; +import com.eclipsesource.json.JsonObject; +import com.eclipsesource.json.JsonValue; +import com.google.common.collect.Iterables; import com.mojang.authlib.AuthenticationService; import com.mojang.authlib.GameProfile; import com.mojang.authlib.exceptions.AuthenticationException; @@ -17,6 +21,7 @@ import com.mojang.authlib.properties.PropertyMap; import launcher.client.ClientLauncher; import launcher.client.PlayerProfile; +import launcher.helper.IOHelper; import launcher.helper.LogHelper; import launcher.helper.SecurityHelper; import launcher.request.auth.CheckServerRequest; @@ -69,21 +74,25 @@ // Add textures if (!NO_TEXTURES) { // Add skin URL to textures map - Iterator skinURL = profile.getProperties().get(ClientLauncher.SKIN_URL_PROPERTY).iterator(); - Iterator skinHash = profile.getProperties().get(ClientLauncher.SKIN_DIGEST_PROPERTY).iterator(); - if (skinURL.hasNext() && skinHash.hasNext()) { - String urlValue = skinURL.next().getValue(); - String hashValue = skinHash.next().getValue(); - textures.put(Type.SKIN, new MinecraftProfileTexture(urlValue, hashValue)); + Property skinURL = Iterables.getFirst(profile.getProperties().get(ClientLauncher.SKIN_URL_PROPERTY), null); + Property skinDigest = Iterables.getFirst(profile.getProperties().get(ClientLauncher.SKIN_DIGEST_PROPERTY), null); + if (skinURL != null && skinDigest != null) { + textures.put(Type.SKIN, new MinecraftProfileTexture(skinURL.getValue(), skinDigest.getValue())); } // Add cloak URL to textures map - Iterator cloakURL = profile.getProperties().get(ClientLauncher.CLOAK_URL_PROPERTY).iterator(); - Iterator cloakHash = profile.getProperties().get(ClientLauncher.CLOAK_DIGEST_PROPERTY).iterator(); - if (cloakURL.hasNext() && cloakHash.hasNext()) { - String urlValue = cloakURL.next().getValue(); - String hashValue = cloakHash.next().getValue(); - textures.put(Type.CAPE, new MinecraftProfileTexture(urlValue, hashValue)); + Property cloakURL = Iterables.getFirst(profile.getProperties().get(ClientLauncher.CLOAK_URL_PROPERTY), null); + Property cloakDigest = Iterables.getFirst(profile.getProperties().get(ClientLauncher.CLOAK_DIGEST_PROPERTY), null); + if (cloakURL != null && cloakDigest != null) { + textures.put(Type.CAPE, new MinecraftProfileTexture(cloakURL.getValue(), cloakDigest.getValue())); + } + + // Try to find missing textures in textures payload (now always true because launcher is not passing elytra skins) + if (textures.size() != MinecraftProfileTexture.PROFILE_TEXTURE_COUNT) { + Property texturesMojang = Iterables.getFirst(profile.getProperties().get("textures"), null); + if (texturesMojang != null) { + getTexturesMojang(textures, texturesMojang.getValue(), profile.getName()); + } } } @@ -163,4 +172,33 @@ fillTextureProperties(profile, pp); return profile; } + + private static void getTexturesMojang(Map textures, String texturesBase64, String username) { + // Decode textures payload + JsonObject texturesJSON; + try { + byte[] decoded = Base64.getDecoder().decode(texturesBase64); + texturesJSON = Json.parse(new String(decoded, IOHelper.UNICODE_CHARSET)).asObject(). + get("textures").asObject(); + } catch (Exception ignored) { + LogHelper.error("Could not decode textures payload, username: '%s'", username); + return; + } + + // Fetch textures from textures JSON + for (Type type : MinecraftProfileTexture.PROFILE_TEXTURE_TYPES) { + if (textures.containsKey(type)) { + continue; // Overriden by launcher + } + + // Get texture from JSON + JsonValue textureJSON = texturesJSON.get(type.name()); + if (textureJSON != null && textureJSON.isObject()) { + JsonValue urlValue = textureJSON.asObject().get("url"); + if (urlValue.isString()) { + textures.put(type, new MinecraftProfileTexture(urlValue.asString())); + } + } + } + } } diff --git a/compat/BungeeCord.patch b/compat/BungeeCord.patch index c5f2cb3..897c6ba 100644 --- a/compat/BungeeCord.patch +++ b/compat/BungeeCord.patch @@ -3,7 +3,7 @@ Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== ---- bootstrap/pom.xml (revision 53cc3242e1d2786c34b2e138d233c4eeca8e3b1d) +--- bootstrap/pom.xml (revision 16d261553c1a648ce38101bda19b7166d1ca5a41) +++ bootstrap/pom.xml (revision ) @@ -57,7 +57,8 @@ @@ -20,14 +20,24 @@ Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== ---- proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java (revision 53cc3242e1d2786c34b2e138d233c4eeca8e3b1d) +--- proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java (revision 16d261553c1a648ce38101bda19b7166d1ca5a41) +++ proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java (revision ) -@@ -8,10 +8,13 @@ +@@ -2,6 +2,7 @@ + + import com.google.common.base.Charsets; + import com.google.common.base.Preconditions; ++import com.google.common.util.concurrent.ThreadFactoryBuilder; + import com.google.gson.Gson; + import java.math.BigInteger; + import java.net.InetAddress; +@@ -9,10 +10,15 @@ import java.net.URLEncoder; import java.security.MessageDigest; import java.util.List; +import java.util.Map; import java.util.UUID; ++import java.util.concurrent.ExecutorService; ++import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import javax.crypto.SecretKey; @@ -36,7 +46,16 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import net.md_5.bungee.BungeeCord; -@@ -261,7 +264,7 @@ +@@ -103,6 +109,8 @@ + private boolean legacy; + @Getter + private String extraDataInHandshake = ""; ++ private ExecutorService loginExecutor = Executors.newCachedThreadPool(new ThreadFactoryBuilder(). ++ setNameFormat("Login Thread #%1$d").setDaemon(true).build()); + + @Override + public boolean shouldHandle(PacketWrapper packet) throws Exception +@@ -263,7 +271,7 @@ this.handshake = handshake; ch.setVersion( handshake.getProtocolVersion() ); @@ -45,14 +64,15 @@ // with Bungee's IP forwarding, so we detect it, and remove it from the host string, for now. // We know FML appends \00FML\00. However, we need to also consider that other systems might // add their own data to the end of the string. So, we just take everything from the \0 character -@@ -402,35 +405,26 @@ +@@ -404,37 +412,27 @@ { 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; -- +- String preventProxy = ( ( BungeeCord.getInstance().config.isPreventProxyConnections() ) ? "&ip=" + URLEncoder.encode( getAddress().getAddress().getHostAddress(), "UTF-8" ) : "" ); +- String authURL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" + encName + "&serverId=" + encodedHash + preventProxy; + - Callback handler = new Callback() - { - @Override @@ -61,9 +81,10 @@ - if ( error == null ) - { - LoginResult obj = BungeeCord.getInstance().gson.fromJson( result, LoginResult.class ); -- if ( obj != null ) +- if ( obj != null && obj.getId() != null ) - { - loginProfile = obj; +- name = obj.getName(); - uniqueId = Util.getUUID( obj.getId() ); - finish(); - return; @@ -75,7 +96,7 @@ - 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(() -> { ++ loginExecutor.submit(() -> { + try { + Map properties = LegacyBridge.checkServerWithProperties(username, serverID); + if(properties == null) { // Invalid username or serverID @@ -103,7 +124,7 @@ Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== ---- bootstrap/src/main/java/net/md_5/bungee/Bootstrap.java (revision 53cc3242e1d2786c34b2e138d233c4eeca8e3b1d) +--- bootstrap/src/main/java/net/md_5/bungee/Bootstrap.java (revision 16d261553c1a648ce38101bda19b7166d1ca5a41) +++ bootstrap/src/main/java/net/md_5/bungee/Bootstrap.java (revision ) @@ -5,9 +5,9 @@ @@ -122,7 +143,7 @@ Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== ---- proxy/src/main/java/net/md_5/bungee/connection/LoginResult.java (revision 53cc3242e1d2786c34b2e138d233c4eeca8e3b1d) +--- proxy/src/main/java/net/md_5/bungee/connection/LoginResult.java (revision 16d261553c1a648ce38101bda19b7166d1ca5a41) +++ proxy/src/main/java/net/md_5/bungee/connection/LoginResult.java (revision ) @@ -1,5 +1,8 @@ package net.md_5.bungee.connection; @@ -133,8 +154,8 @@ import lombok.AllArgsConstructor; import lombok.Data; -@@ -11,6 +14,17 @@ - private String id; +@@ -12,6 +15,17 @@ + private String name; private Property[] properties; + public LoginResult(Map propertiesMap) { @@ -156,7 +177,7 @@ Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== ---- pom.xml (revision 53cc3242e1d2786c34b2e138d233c4eeca8e3b1d) +--- pom.xml (revision 16d261553c1a648ce38101bda19b7166d1ca5a41) +++ pom.xml (revision ) @@ -67,8 +67,8 @@ @@ -176,7 +197,7 @@ + + launcher + clientside -+ 13.4+ ++ 15.4+ + system + /full/path/to/Launcher.jar + diff --git a/compat/authlib/authlib-clean.jar b/compat/authlib/authlib-clean.jar index 4f5361a..15708bb 100644 --- a/compat/authlib/authlib-clean.jar +++ b/compat/authlib/authlib-clean.jar Binary files differ