Merge pull request #19 from yushijinhun/ali

实现 #16, #17, #18
This commit is contained in:
Haowei Wen 2018-10-06 12:50:24 +08:00 committed by GitHub
commit 7d90d7cb78
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 111 additions and 3 deletions

View file

@ -3,12 +3,16 @@ package moe.yushi.authlibinjector;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Optional.empty;
import static java.util.Optional.of;
import static moe.yushi.authlibinjector.util.IOUtils.asBytes;
import static moe.yushi.authlibinjector.util.IOUtils.asString;
import static moe.yushi.authlibinjector.util.IOUtils.getURL;
import static moe.yushi.authlibinjector.util.IOUtils.removeNewLines;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.instrument.ClassFileTransformer;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Base64;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
@ -61,8 +65,18 @@ public final class AuthlibInjector {
*/
public static final String PROP_DUMP_CLASS = "authlibinjector.dumpClass";
/**
* The side that authlib-injector runs on.
* Possible values: client, server.
*/
public static final String PROP_SIDE = "authlibinjector.side";
public static final String PROP_ALI_REDIRECT_LIMIT = "authlibinjector.ali.redirectLimit";
// ====
private static final int REDIRECT_LIMIT = Integer.getInteger(PROP_ALI_REDIRECT_LIMIT, 5);
private AuthlibInjector() {}
private static AtomicBoolean booted = new AtomicBoolean(false);
@ -99,7 +113,10 @@ public final class AuthlibInjector {
String apiRoot = System.getProperty(PROP_API_ROOT);
if (apiRoot == null) return empty();
apiRoot = appendSuffixSlash(apiRoot);
ExecutionEnvironment side = detectSide();
Logging.LAUNCH.fine("Detected side: " + side);
apiRoot = parseInputUrl(apiRoot);
Logging.CONFIG.info("API root: " + apiRoot);
warnIfHttp(apiRoot);
@ -107,8 +124,40 @@ public final class AuthlibInjector {
Optional<String> prefetched = getPrefetchedResponse();
if (!prefetched.isPresent()) {
try {
metadataResponse = asString(getURL(apiRoot));
HttpURLConnection connection;
boolean redirectAllowed = side == ExecutionEnvironment.SERVER;
int redirectCount = 0;
for (;;) {
connection = (HttpURLConnection) new URL(apiRoot).openConnection();
Optional<String> ali = getApiLocationIndication(connection);
if (ali.isPresent()) {
if (!redirectAllowed) {
Logging.CONFIG.warning("Redirect is not allowed, ignoring ALI: " + ali.get());
break;
}
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);
warnIfHttp(apiRoot);
} else {
break;
}
}
try {
metadataResponse = asString(asBytes(connection.getInputStream()));
} finally {
connection.disconnect();
}
} catch (IOException e) {
Logging.CONFIG.severe("Failed to fetch metadata: " + e);
throw new InjectorInitializationException(e);
@ -155,6 +204,60 @@ public final class AuthlibInjector {
}
}
private static String parseInputUrl(String url) {
String lowercased = url.toLowerCase();
if (!lowercased.startsWith("http://") && !lowercased.startsWith("https://")) {
url = "https://" + url;
}
url = appendSuffixSlash(url);
return url;
}
private static Optional<String> 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 ClassTransformer createTransformer(YggdrasilConfiguration config) {
ClassTransformer transformer = new ClassTransformer();
transformer.debugSaveClass = "true".equals(System.getProperty(PROP_DUMP_CLASS));

View file

@ -0,0 +1,5 @@
package moe.yushi.authlibinjector;
public enum ExecutionEnvironment {
CLIENT, SERVER;
}