diff --git a/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java b/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java index 8ff4a55..61703cc 100644 --- a/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java +++ b/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 Haowei Wen and contributors + * Copyright (C) 2023 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 @@ -46,12 +46,14 @@ import moe.yushi.authlibinjector.httpd.DefaultURLRedirector; import moe.yushi.authlibinjector.httpd.LegacySkinAPIFilter; import moe.yushi.authlibinjector.httpd.ProfileKeyFilter; +import moe.yushi.authlibinjector.httpd.PublickeysFilter; import moe.yushi.authlibinjector.httpd.QueryProfileFilter; import moe.yushi.authlibinjector.httpd.QueryUUIDsFilter; import moe.yushi.authlibinjector.httpd.URLFilter; import moe.yushi.authlibinjector.httpd.URLProcessor; import moe.yushi.authlibinjector.transform.ClassTransformer; import moe.yushi.authlibinjector.transform.DumpClassListener; +import moe.yushi.authlibinjector.transform.support.AccountTypeTransformer; import moe.yushi.authlibinjector.transform.support.AuthServerNameInjector; import moe.yushi.authlibinjector.transform.support.AuthlibLogInterceptor; import moe.yushi.authlibinjector.transform.support.BungeeCordAllowedCharactersTransformer; @@ -257,6 +259,8 @@ private static List createFilters(APIMetadata config) { filters.add(new ProfileKeyFilter()); } + filters.add(new PublickeysFilter()); + return filters; } @@ -295,6 +299,7 @@ private static ClassTransformer createTransformer(APIMetadata config) { config.getDecodedPublickey().ifPresent(YggdrasilKeyTransformUnit.PUBLIC_KEYS::add); transformer.units.add(new VelocityProfileKeyTransformUnit()); transformer.units.add(new BungeeCordProfileKeyTransformUnit()); + MainArgumentsTransformer.getArgumentsListeners().add(new AccountTypeTransformer()::transform); return transformer; } diff --git a/src/main/java/moe/yushi/authlibinjector/httpd/PublickeysFilter.java b/src/main/java/moe/yushi/authlibinjector/httpd/PublickeysFilter.java new file mode 100644 index 0000000..c17cd5e --- /dev/null +++ b/src/main/java/moe/yushi/authlibinjector/httpd/PublickeysFilter.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2023 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.httpd; + +import static moe.yushi.authlibinjector.util.IOUtils.CONTENT_TYPE_JSON; +import java.io.IOException; +import java.security.PublicKey; +import java.util.Base64; +import java.util.Optional; +import moe.yushi.authlibinjector.internal.fi.iki.elonen.IHTTPSession; +import moe.yushi.authlibinjector.internal.fi.iki.elonen.Response; +import moe.yushi.authlibinjector.internal.fi.iki.elonen.Status; +import moe.yushi.authlibinjector.internal.org.json.simple.JSONArray; +import moe.yushi.authlibinjector.internal.org.json.simple.JSONObject; +import moe.yushi.authlibinjector.transform.support.YggdrasilKeyTransformUnit; + +public class PublickeysFilter implements URLFilter { + + @Override + public boolean canHandle(String domain) { + return domain.equals("api.minecraftservices.com"); + } + + @Override + public Optional handle(String domain, String path, IHTTPSession session) throws IOException { + if (domain.equals("api.minecraftservices.com") && path.equals("/publickeys") && session.getMethod().equals("GET")) { + return Optional.of(Response.newFixedLength(Status.OK, CONTENT_TYPE_JSON, makePublickeysResponse().toJSONString())); + } + return Optional.empty(); + } + + private JSONObject makePublickeysResponse() { + JSONObject response = new JSONObject(); + JSONArray profilePropertyKeys = new JSONArray(); + JSONArray playerCertificateKeys = new JSONArray(); + + for (PublicKey key : YggdrasilKeyTransformUnit.PUBLIC_KEYS) { + JSONObject entry = new JSONObject(); + entry.put("publicKey", Base64.getEncoder().encodeToString(key.getEncoded())); + profilePropertyKeys.add(entry); + playerCertificateKeys.add(entry); + } + + response.put("profilePropertyKeys", profilePropertyKeys); + response.put("playerCertificateKeys", playerCertificateKeys); + return response; + } +} diff --git a/src/main/java/moe/yushi/authlibinjector/transform/support/AccountTypeTransformer.java b/src/main/java/moe/yushi/authlibinjector/transform/support/AccountTypeTransformer.java new file mode 100644 index 0000000..01a32fa --- /dev/null +++ b/src/main/java/moe/yushi/authlibinjector/transform/support/AccountTypeTransformer.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023 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.transform.support; + +import static moe.yushi.authlibinjector.util.Logging.log; +import static moe.yushi.authlibinjector.util.Logging.Level.INFO; + +public class AccountTypeTransformer { + + public String[] transform(String[] args) { + boolean userTypeMatched = false; + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if ("--userType".equals(arg)) { + userTypeMatched = true; + } else if (userTypeMatched && "mojang".equals(arg)) { + args[i] = "msa"; + log(INFO, "Setting accountType to msa"); + break; + } + } + return args; + } + +} diff --git a/src/main/java/moe/yushi/authlibinjector/transform/support/AuthlibLogInterceptor.java b/src/main/java/moe/yushi/authlibinjector/transform/support/AuthlibLogInterceptor.java index a09836f..c5a1042 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/support/AuthlibLogInterceptor.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/support/AuthlibLogInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 Haowei Wen and contributors + * Copyright (C) 2023 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 @@ -128,7 +128,18 @@ private static void registerLogHandle(ClassLoader cl) throws ReflectiveOperation Array.set(appenderRefs, 0, appenderRef); Object loggerConfig; - { + try { + Object builder = classLoggerConfig.getDeclaredMethod("newBuilder").invoke(null); + Class classBuilder = cl.loadClass("org.apache.logging.log4j.core.config.LoggerConfig$Builder"); + classBuilder.getMethod("withConfig", classConfiguration).invoke(builder, configuration); + classBuilder.getMethod("withAdditivity", boolean.class).invoke(builder, false); + classBuilder.getMethod("withLevel", classLevel).invoke(builder, classLevel.getDeclaredField("ALL").get(null)); + classBuilder.getMethod("withLoggerName", String.class).invoke(builder, loggerName); + classBuilder.getMethod("withIncludeLocation", String.class).invoke(builder, authlibPackageName); + classBuilder.getMethod("withRefs", appenderRefs.getClass()).invoke(builder, appenderRefs); + loggerConfig = classBuilder.getMethod("build").invoke(builder); + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); Map values = new HashMap<>(); values.put("additivity", false); values.put("level", classLevel.getDeclaredField("ALL").get(null));