From 6569238649598253a3ea1f098c1035ac22d5d831 Mon Sep 17 00:00:00 2001 From: yushijinhun Date: Sat, 5 Jan 2019 22:39:24 +0800 Subject: [PATCH] Only turn on MC-52974 workaround for affected versions --- .../authlibinjector/AuthlibInjector.java | 14 +++- .../httpd/QueryProfileFilter.java | 14 ++-- .../transform/MainArgumentsTransformer.java | 71 ++++++++++++++++ .../transform/support/MC52974Workaround.java | 60 ++++++++++++++ .../test/MC52974WorkaroundTest.java | 82 +++++++++++++++++++ 5 files changed, 231 insertions(+), 10 deletions(-) create mode 100644 src/main/java/moe/yushi/authlibinjector/transform/MainArgumentsTransformer.java create mode 100644 src/main/java/moe/yushi/authlibinjector/transform/support/MC52974Workaround.java create mode 100644 src/test/java/moe/yushi/authlibinjector/test/MC52974WorkaroundTest.java diff --git a/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java b/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java index b3fe885..59d8e82 100644 --- a/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java +++ b/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java @@ -23,6 +23,7 @@ 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.removeNewLines; + import java.io.IOException; import java.io.UncheckedIOException; import java.lang.instrument.ClassFileTransformer; @@ -48,10 +49,12 @@ import moe.yushi.authlibinjector.transform.AuthlibLogInterceptor; import moe.yushi.authlibinjector.transform.ClassTransformer; import moe.yushi.authlibinjector.transform.ConstantURLTransformUnit; import moe.yushi.authlibinjector.transform.DumpClassListener; +import moe.yushi.authlibinjector.transform.MainArgumentsTransformer; import moe.yushi.authlibinjector.transform.SkinWhitelistTransformUnit; import moe.yushi.authlibinjector.transform.YggdrasilKeyTransformUnit; import moe.yushi.authlibinjector.transform.support.CitizensTransformer; import moe.yushi.authlibinjector.transform.support.LaunchWrapperTransformer; +import moe.yushi.authlibinjector.transform.support.MC52974Workaround; import moe.yushi.authlibinjector.util.Logging; import moe.yushi.authlibinjector.yggdrasil.CustomYggdrasilAPIProvider; import moe.yushi.authlibinjector.yggdrasil.MojangYggdrasilAPIProvider; @@ -310,7 +313,15 @@ public final class AuthlibInjector { } filters.add(new QueryUUIDsFilter(mojangClient, customClient)); - filters.add(new QueryProfileFilter(mojangClient, customClient)); + QueryProfileFilter queryProfileFilter = new QueryProfileFilter(mojangClient, customClient); + filters.add(queryProfileFilter); + + MC52974Workaround mc52974 = new MC52974Workaround(); + MainArgumentsTransformer.getListeners().add(args -> { + mc52974.acceptMainArguments(args); + return args; + }); + queryProfileFilter.setMc52974Workaround(mc52974); return filters; } @@ -331,6 +342,7 @@ public final class AuthlibInjector { transformer.units.add(new AuthlibLogInterceptor()); } + transformer.units.add(new MainArgumentsTransformer()); transformer.units.add(new ConstantURLTransformUnit(urlProcessor)); transformer.units.add(new CitizensTransformer()); transformer.units.add(new LaunchWrapperTransformer()); diff --git a/src/main/java/moe/yushi/authlibinjector/httpd/QueryProfileFilter.java b/src/main/java/moe/yushi/authlibinjector/httpd/QueryProfileFilter.java index 39fffe6..4c1b133 100644 --- a/src/main/java/moe/yushi/authlibinjector/httpd/QueryProfileFilter.java +++ b/src/main/java/moe/yushi/authlibinjector/httpd/QueryProfileFilter.java @@ -29,6 +29,7 @@ import java.util.regex.Pattern; 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.transform.support.MC52974Workaround; import moe.yushi.authlibinjector.yggdrasil.GameProfile; import moe.yushi.authlibinjector.yggdrasil.YggdrasilClient; import moe.yushi.authlibinjector.yggdrasil.YggdrasilResponseBuilder; @@ -40,8 +41,7 @@ public class QueryProfileFilter implements URLFilter { private YggdrasilClient mojangClient; private YggdrasilClient customClient; - // see - private boolean mc52974WorkaroundEnabled; + private MC52974Workaround mc52974Workaround; public QueryProfileFilter(YggdrasilClient mojangClient, YggdrasilClient customClient) { this.mojangClient = mojangClient; @@ -74,7 +74,7 @@ public class QueryProfileFilter implements URLFilter { withSignature = true; } - if (mc52974WorkaroundEnabled) { + if (mc52974Workaround != null && mc52974Workaround.needsWorkaround()) { withSignature = true; } @@ -96,11 +96,7 @@ public class QueryProfileFilter implements URLFilter { } } - public boolean isMc52974WorkaroundEnabled() { - return mc52974WorkaroundEnabled; - } - - public void setMc52974WorkaroundEnabled(boolean mc52974WorkaroundEnabled) { - this.mc52974WorkaroundEnabled = mc52974WorkaroundEnabled; + public void setMc52974Workaround(MC52974Workaround mc52974Workaround) { + this.mc52974Workaround = mc52974Workaround; } } diff --git a/src/main/java/moe/yushi/authlibinjector/transform/MainArgumentsTransformer.java b/src/main/java/moe/yushi/authlibinjector/transform/MainArgumentsTransformer.java new file mode 100644 index 0000000..42c62ed --- /dev/null +++ b/src/main/java/moe/yushi/authlibinjector/transform/MainArgumentsTransformer.java @@ -0,0 +1,71 @@ +package moe.yushi.authlibinjector.transform; + +import static java.util.stream.Collectors.joining; +import static org.objectweb.asm.Opcodes.ALOAD; +import static org.objectweb.asm.Opcodes.ASM7; +import static org.objectweb.asm.Opcodes.ASTORE; +import static org.objectweb.asm.Opcodes.INVOKESTATIC; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Function; +import java.util.stream.Stream; + +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Type; + +import moe.yushi.authlibinjector.util.Logging; + +public class MainArgumentsTransformer implements TransformUnit { + + private static final List> LISTENERS = new CopyOnWriteArrayList<>(); + + public static String[] processMainArguments(String[] args) { + Logging.TRANSFORM.fine(() -> "Main arguments: " + Stream.of(args).collect(joining(" "))); + + String[] result = args; + for (Function listener : LISTENERS) { + result = listener.apply(result); + } + return result; + } + + public static List> getListeners() { + return LISTENERS; + } + + @Override + public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) { + if ("net.minecraft.client.main.Main".equals(className)) { + return Optional.of(new ClassVisitor(ASM7, writer) { + @Override + public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { + if ("main".equals(name) && "([Ljava/lang/String;)V".equals(descriptor)) { + return new MethodVisitor(ASM7, super.visitMethod(access, name, descriptor, signature, exceptions)) { + @Override + public void visitCode() { + super.visitCode(); + modifiedCallback.run(); + + super.visitVarInsn(ALOAD, 0); + super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(MainArgumentsTransformer.class), "processMainArguments", "([Ljava/lang/String;)[Ljava/lang/String;", false); + super.visitVarInsn(ASTORE, 0); + } + }; + } else { + return super.visitMethod(access, name, descriptor, signature, exceptions); + } + } + }); + } else { + return Optional.empty(); + } + } + + @Override + public String toString() { + return "Main Arguments Transformer"; + } +} diff --git a/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974Workaround.java b/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974Workaround.java new file mode 100644 index 0000000..caa67f1 --- /dev/null +++ b/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974Workaround.java @@ -0,0 +1,60 @@ +package moe.yushi.authlibinjector.transform.support; + +import static java.util.Collections.unmodifiableSet; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import moe.yushi.authlibinjector.util.Logging; + +/** + * See + */ +public class MC52974Workaround { + + private static final Set AFFECTED_VERSION_SERIES = unmodifiableSet(new HashSet<>(Arrays.asList( + "1.7.4", // MC 1.7.9 uses this + "1.7.10", + "1.8", + "1.9", + "1.10", + "1.11", + "1.12"))); + + private boolean enabled; + + public boolean needsWorkaround() { + return enabled; + } + + public void acceptMainArguments(String[] args) { + parseArgument(args, "--assetIndex").ifPresent(assetIndexName -> { + if (AFFECTED_VERSION_SERIES.contains(assetIndexName)) { + Logging.HTTPD.info("Current version series is " + assetIndexName + ", enable MC-52974 workaround."); + enabled = true; + } + }); + } + + private static Optional parseArgument(String[] args, String option) { + boolean hit = false; + for (String arg : args) { + if (hit) { + if (arg.startsWith("--")) { + // arg doesn't seem to be a value + // maybe the previous argument is a value, but we wrongly recognized it as an option + hit = false; + } else { + return Optional.of(arg); + } + } + + if (option.equals(arg)) { + hit = true; + } + } + return Optional.empty(); + } +} diff --git a/src/test/java/moe/yushi/authlibinjector/test/MC52974WorkaroundTest.java b/src/test/java/moe/yushi/authlibinjector/test/MC52974WorkaroundTest.java new file mode 100644 index 0000000..9d6e17d --- /dev/null +++ b/src/test/java/moe/yushi/authlibinjector/test/MC52974WorkaroundTest.java @@ -0,0 +1,82 @@ +package moe.yushi.authlibinjector.test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import moe.yushi.authlibinjector.transform.support.MC52974Workaround; + +public class MC52974WorkaroundTest { + + private boolean checkEnabled(String args) { + MC52974Workaround workaround = new MC52974Workaround(); + workaround.acceptMainArguments(args.split(" ")); + return workaround.needsWorkaround(); + } + + @Test + public void testNone() { + assertFalse(checkEnabled("")); + } + + @Test + public void testHalf1() { + assertFalse(checkEnabled("--assetIndex")); + } + + @Test + public void testHalf2() { + assertFalse(checkEnabled("--width 854 --height 480 --username character2 --version \"HMCL 3.2.SNAPSHOT\" --gameDir /home/yushijinhun/.minecraft --assetsDir /home/yushijinhun/.minecraft/assets --assetIndex")); + } + + @Test + public void testAmbiguity1() { + assertFalse(checkEnabled("--username --assetIndex")); + } + + @Test + public void testAmbiguity2() { + assertTrue(checkEnabled("--demo --assetIndex 1.12")); + } + + @Test + public void test1_7_9() { + assertTrue(checkEnabled("--width 854 --height 480 --username character2 --version \"HMCL 3.2.SNAPSHOT\" --gameDir /home/yushijinhun/.minecraft --assetsDir /home/yushijinhun/.minecraft/assets --assetIndex 1.7.4 --uuid e448fdeff6394b3fac7aecc291446329 --accessToken 65a7fe601b02439fa90bea52b7d46ab5 --userProperties \"{}\" --userType mojang")); + } + + @Test + public void test1_7_10() { + assertTrue(checkEnabled("--width 854 --height 480 --username character2 --version \"HMCL 3.2.SNAPSHOT\" --gameDir /home/yushijinhun/.minecraft --assetsDir /home/yushijinhun/.minecraft/assets --assetIndex 1.7.10 --uuid e448fdeff6394b3fac7aecc291446329 --accessToken 65a7fe601b02439fa90bea52b7d46ab5 --userProperties \"{}\" --userType mojang")); + } + + @Test + public void test1_8_9() { + assertTrue(checkEnabled("--width 854 --height 480 --username character2 --version \"HMCL 3.2.SNAPSHOT\" --gameDir /home/yushijinhun/.minecraft --assetsDir /home/yushijinhun/.minecraft/assets --assetIndex 1.8 --uuid e448fdeff6394b3fac7aecc291446329 --accessToken 65a7fe601b02439fa90bea52b7d46ab5 --userProperties \"{}\" --userType mojang")); + } + + @Test + public void test1_9_4() { + assertTrue(checkEnabled("--width 854 --height 480 --username character2 --version \"HMCL 3.2.SNAPSHOT\" --gameDir /home/yushijinhun/.minecraft --assetsDir /home/yushijinhun/.minecraft/assets --assetIndex 1.9 --uuid e448fdeff6394b3fac7aecc291446329 --accessToken 65a7fe601b02439fa90bea52b7d46ab5 --userType mojang --versionType release")); + } + + @Test + public void test1_10_2_Forge() { + assertTrue(checkEnabled("--width 854 --height 480 --username character2 --version \"HMCL 3.2.SNAPSHOT\" --gameDir /home/yushijinhun/.minecraft --assetsDir /home/yushijinhun/.minecraft/assets --assetIndex 1.10 --uuid e448fdeff6394b3fac7aecc291446329 --accessToken 65a7fe601b02439fa90bea52b7d46ab5 --userType mojang --versionType Forge")); + } + + @Test + public void test1_11_2() { + assertTrue(checkEnabled("--width 854 --height 480 --username character2 --version \"HMCL 3.2.SNAPSHOT\" --gameDir /home/yushijinhun/.minecraft --assetsDir /home/yushijinhun/.minecraft/assets --assetIndex 1.11 --uuid e448fdeff6394b3fac7aecc291446329 --accessToken 65a7fe601b02439fa90bea52b7d46ab5 --userType mojang --versionType release")); + } + + @Test + public void test1_12_2() { + assertTrue(checkEnabled("--width 854 --height 480 --username character2 --version \"HMCL 3.2.SNAPSHOT\" --gameDir /home/yushijinhun/.minecraft --assetsDir /home/yushijinhun/.minecraft/assets --assetIndex 1.12 --uuid e448fdeff6394b3fac7aecc291446329 --accessToken 65a7fe601b02439fa90bea52b7d46ab5 --userType mojang --versionType release")); + } + + @Test + public void test1_13() { + assertFalse(checkEnabled("--username character2 --version \"HMCL 3.2.SNAPSHOT\" --gameDir /home/yushijinhun/.minecraft --assetsDir /home/yushijinhun/.minecraft/assets --assetIndex 1.13 --uuid e448fdeff6394b3fac7aecc291446329 --accessToken 65a7fe601b02439fa90bea52b7d46ab5 --userType mojang --versionType release --width 854 --height 480")); + } +}