diff --git a/build.gradle b/build.gradle index 03648dc..d8bebab 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.github.johnrengelman.shadow' version '5.2.0' + id 'com.github.johnrengelman.shadow' version '6.0.0' id 'com.palantir.git-version' version '0.12.3' id 'java' } @@ -9,8 +9,8 @@ repositories { } dependencies { - compile 'org.ow2.asm:asm:8.0.1' - testCompile 'junit:junit:4.13' + implementation 'org.ow2.asm:asm:8.0.1' + testImplementation 'junit:junit:4.13' } sourceCompatibility = 8 @@ -24,7 +24,7 @@ jar { manifest { attributes ( 'Implementation-Title': project.name, - 'Implementation-Version': version, + 'Implementation-Version': project.version, 'Implementation-Vendor': 'yushijinhun', 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), 'Automatic-Module-Name': 'moe.yushi.authlibinjector', diff --git a/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java b/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java index 897c3b4..ed35741 100644 --- a/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java +++ b/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java @@ -25,14 +25,13 @@ import static moe.yushi.authlibinjector.util.IOUtils.removeNewLines; import java.io.IOException; +import java.io.InputStream; import java.io.UncheckedIOException; import java.lang.instrument.Instrumentation; import java.net.HttpURLConnection; import java.net.InetSocketAddress; -import java.net.MalformedURLException; import java.net.Proxy; import java.net.URL; -import java.net.URLConnection; import java.net.Proxy.Type; import java.nio.file.Paths; import java.util.ArrayList; @@ -114,16 +113,8 @@ public final class AuthlibInjector { */ public static final String PROP_IGNORED_PACKAGES = "authlibinjector.ignoredPackages"; - /** - * The side that authlib-injector runs on. - * Possible values: client, server. - */ - public static final String PROP_SIDE = "authlibinjector.side"; - public static final String PROP_DISABLE_HTTPD = "authlibinjector.httpd.disable"; - public static final String PROP_ALI_REDIRECT_LIMIT = "authlibinjector.ali.redirectLimit"; - // ==== // ==== Package filtering ==== @@ -187,8 +178,6 @@ public final class AuthlibInjector { } // ==== - private static final int REDIRECT_LIMIT = Integer.getInteger(PROP_ALI_REDIRECT_LIMIT, 5); - private AuthlibInjector() {} private static boolean booted = false; @@ -239,10 +228,7 @@ private static Optional configure() { String apiRoot = System.getProperty(PROP_API_ROOT); if (apiRoot == null) return empty(); - ExecutionEnvironment side = detectSide(); - Logging.LAUNCH.fine("Detected side: " + side); - - apiRoot = parseInputUrl(apiRoot); + apiRoot = addHttpsIfMissing(apiRoot); Logging.CONFIG.info("API root: " + apiRoot); warnIfHttp(apiRoot); @@ -252,37 +238,31 @@ private static Optional configure() { if (!prefetched.isPresent()) { try { - HttpURLConnection connection; - boolean redirectAllowed = side == ExecutionEnvironment.SERVER; - int redirectCount = 0; - for (;;) { - connection = (HttpURLConnection) new URL(apiRoot).openConnection(); - Optional ali = getApiLocationIndication(connection); - if (ali.isPresent()) { - if (!redirectAllowed) { - Logging.CONFIG.warning("Redirect is not allowed, ignoring ALI: " + ali.get()); - break; + HttpURLConnection connection = (HttpURLConnection) new URL(apiRoot).openConnection(); + + String ali = connection.getHeaderField("x-authlib-injector-api-location"); + if (ali != null) { + URL absoluteAli = new URL(connection.getURL(), ali); + if (!urlEqualsIgnoreSlash(apiRoot, absoluteAli.toString())) { + + // usually the URL that ALI points to is on the same host + // so the TCP connection can be reused + // we need to consume the response to make the connection reusable + try (InputStream in = connection.getInputStream()) { + while (in.read() != -1) + ; + } catch (IOException e) { } - connection.disconnect(); - - apiRoot = ali.get(); - if (redirectCount >= REDIRECT_LIMIT) { - Logging.CONFIG.severe("Exceeded maximum number of redirects (" + REDIRECT_LIMIT + "), refusing to redirect to: " + apiRoot); - throw new InjectorInitializationException(); - } - redirectCount++; - Logging.CONFIG.info("Redirect to: " + apiRoot); + Logging.CONFIG.info("Redirect to: " + absoluteAli); + apiRoot = absoluteAli.toString(); warnIfHttp(apiRoot); - } else { - break; + connection = (HttpURLConnection) absoluteAli.openConnection(); } } - try { - metadataResponse = asString(asBytes(connection.getInputStream())); - } finally { - connection.disconnect(); + try (InputStream in = connection.getInputStream()) { + metadataResponse = asString(asBytes(in)); } } catch (IOException e) { Logging.CONFIG.severe("Failed to fetch metadata: " + e); @@ -303,6 +283,9 @@ private static Optional configure() { Logging.CONFIG.fine("Metadata: " + metadataResponse); + if (!apiRoot.endsWith("/")) + apiRoot += "/"; + YggdrasilConfiguration configuration; try { configuration = YggdrasilConfiguration.parse(apiRoot, metadataResponse); @@ -322,66 +305,20 @@ private static void warnIfHttp(String url) { } } - private static String appendSuffixSlash(String url) { - if (!url.endsWith("/")) { - return url + "/"; - } else { - return url; - } - } - - private static String parseInputUrl(String url) { + private static String addHttpsIfMissing(String url) { String lowercased = url.toLowerCase(); if (!lowercased.startsWith("http://") && !lowercased.startsWith("https://")) { url = "https://" + url; } - - url = appendSuffixSlash(url); return url; } - private static Optional getApiLocationIndication(URLConnection conn) { - return Optional.ofNullable(conn.getHeaderFields().get("X-Authlib-Injector-API-Location")) - .flatMap(list -> list.isEmpty() ? Optional.empty() : Optional.of(list.get(0))) - .flatMap(indication -> { - String currentUrl = appendSuffixSlash(conn.getURL().toString()); - String newUrl; - try { - newUrl = appendSuffixSlash(new URL(conn.getURL(), indication).toString()); - } catch (MalformedURLException e) { - Logging.CONFIG.warning("Failed to resolve absolute ALI, the header is [" + indication + "]. Ignore it."); - return Optional.empty(); - } - - if (newUrl.equals(currentUrl)) { - return Optional.empty(); - } else { - return Optional.of(newUrl); - } - }); - } - - private static ExecutionEnvironment detectSide() { - String specifiedSide = System.getProperty(PROP_SIDE); - if (specifiedSide != null) { - switch (specifiedSide) { - case "client": - return ExecutionEnvironment.CLIENT; - case "server": - return ExecutionEnvironment.SERVER; - default: - Logging.LAUNCH.warning("Invalid value [" + specifiedSide + "] for parameter " + PROP_SIDE + ", ignoring."); - break; - } - } - - // fallback - if (System.getProperty(PROP_PREFETCHED_DATA) != null || System.getProperty(PROP_PREFETCHED_DATA_OLD) != null) { - Logging.LAUNCH.warning("Prefetched configuration must be used along with parameter " + PROP_SIDE); - return ExecutionEnvironment.CLIENT; - } else { - return ExecutionEnvironment.SERVER; - } + private static boolean urlEqualsIgnoreSlash(String a, String b) { + if (!a.endsWith("/")) + a += "/"; + if (!b.endsWith("/")) + b += "/"; + return a.equals(b); } private static List createFilters(YggdrasilConfiguration config) { diff --git a/src/main/java/moe/yushi/authlibinjector/ExecutionEnvironment.java b/src/main/java/moe/yushi/authlibinjector/ExecutionEnvironment.java deleted file mode 100644 index a883dea..0000000 --- a/src/main/java/moe/yushi/authlibinjector/ExecutionEnvironment.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2019 Haowei Wen and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package moe.yushi.authlibinjector; - -public enum ExecutionEnvironment { - CLIENT, SERVER; -} diff --git a/src/main/java/moe/yushi/authlibinjector/httpd/QueryProfileFilter.java b/src/main/java/moe/yushi/authlibinjector/httpd/QueryProfileFilter.java index 8c5e944..48a9a33 100644 --- a/src/main/java/moe/yushi/authlibinjector/httpd/QueryProfileFilter.java +++ b/src/main/java/moe/yushi/authlibinjector/httpd/QueryProfileFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Haowei Wen and contributors + * Copyright (C) 2020 Haowei Wen and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -47,7 +47,7 @@ public QueryProfileFilter(YggdrasilClient mojangClient, YggdrasilClient customCl @Override public boolean canHandle(String domain, String path) { - return domain.equals("sessionserver.mojang.com") && path.startsWith("/session/minecraft/profile/"); + return domain.equals("sessionserver.mojang.com"); } @Override diff --git a/src/main/java/moe/yushi/authlibinjector/httpd/QueryUUIDsFilter.java b/src/main/java/moe/yushi/authlibinjector/httpd/QueryUUIDsFilter.java index da64b99..41fc6b9 100644 --- a/src/main/java/moe/yushi/authlibinjector/httpd/QueryUUIDsFilter.java +++ b/src/main/java/moe/yushi/authlibinjector/httpd/QueryUUIDsFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Haowei Wen and contributors + * Copyright (C) 2020 Haowei Wen and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -50,7 +50,7 @@ public QueryUUIDsFilter(YggdrasilClient mojangClient, YggdrasilClient customClie @Override public boolean canHandle(String domain, String path) { - return domain.equals("api.mojang.com") && path.startsWith("/profiles/"); + return domain.equals("api.mojang.com"); } @Override diff --git a/src/main/java/moe/yushi/authlibinjector/util/IOUtils.java b/src/main/java/moe/yushi/authlibinjector/util/IOUtils.java index 22c8723..5d5db2f 100644 --- a/src/main/java/moe/yushi/authlibinjector/util/IOUtils.java +++ b/src/main/java/moe/yushi/authlibinjector/util/IOUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Haowei Wen and contributors + * Copyright (C) 2020 Haowei Wen and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -58,7 +58,6 @@ public static byte[] http(String method, String url, byte[] payload, String cont HttpURLConnection conn = createConnection(url, proxy); conn.setRequestMethod(method); conn.setDoOutput(true); - conn.setFixedLengthStreamingMode(payload.length); conn.setRequestProperty("Content-Type", contentType); try (OutputStream out = conn.getOutputStream()) { out.write(payload);