Refactor transform

This commit is contained in:
yushijinhun 2018-09-23 22:45:45 +08:00
parent 1a1f9fc8fc
commit 8c615b618b
No known key found for this signature in database
GPG key ID: 5BC167F73EA558E4
10 changed files with 95 additions and 86 deletions

View file

@ -13,10 +13,10 @@ import java.util.Base64;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import moe.yushi.authlibinjector.httpd.LocalYggdrasilHandle;
import moe.yushi.authlibinjector.transform.ClassTransformer;
import moe.yushi.authlibinjector.transform.SkinWhitelistTransformUnit;
import moe.yushi.authlibinjector.transform.YggdrasilApiTransformUnit;
import moe.yushi.authlibinjector.transform.LocalYggdrasilApiTransformUnit;
import moe.yushi.authlibinjector.transform.RemoteYggdrasilTransformUnit;
import moe.yushi.authlibinjector.transform.YggdrasilKeyTransformUnit;
import moe.yushi.authlibinjector.util.Logging;
@ -143,10 +143,10 @@ public final class AuthlibInjector {
transformer.ignores.add(ignore);
if (!"true".equals(System.getProperty(PROP_DISABLE_HTTPD))) {
transformer.units.add(LocalYggdrasilHandle.createTransformUnit(config));
transformer.units.add(new LocalYggdrasilApiTransformUnit(config));
}
transformer.units.add(new YggdrasilApiTransformUnit(config.getApiRoot()));
transformer.units.add(new RemoteYggdrasilTransformUnit(config.getApiRoot()));
transformer.units.add(new SkinWhitelistTransformUnit(config.getSkinDomains().toArray(new String[0])));

View file

@ -2,20 +2,10 @@ package moe.yushi.authlibinjector.httpd;
import java.io.IOException;
import moe.yushi.authlibinjector.YggdrasilConfiguration;
import moe.yushi.authlibinjector.transform.LocalYggdrasilApiTransformUnit;
import moe.yushi.authlibinjector.transform.TransformUnit;
import moe.yushi.authlibinjector.util.Logging;
public class LocalYggdrasilHandle {
public static TransformUnit createTransformUnit(YggdrasilConfiguration configuration) {
LocalYggdrasilHandle handle = new LocalYggdrasilHandle(configuration);
return new LocalYggdrasilApiTransformUnit(() -> {
handle.ensureStarted();
return "http://127.0.0.1:" + handle.getLocalApiPort();
});
}
private boolean started = false;
private YggdrasilConfiguration configuration;
private LocalYggdrasilHttpd httpd;

View file

@ -33,8 +33,7 @@ public class LocalYggdrasilHttpd extends NanoHTTPD {
public static final String CONTENT_TYPE_JSON = "application/json; charset=utf-8";
// ^/MinecraftSkins/([^/]+)\.png$
private static final Pattern URL_SKINS = Pattern.compile("^/MinecraftSkins/(?<username>[^/]+)\\.png$");
private static final Pattern URL_SKINS = Pattern.compile("^/skins/MinecraftSkins/(?<username>[^/]+)\\.png$");
private YggdrasilConfiguration configuration;

View file

@ -0,0 +1,38 @@
package moe.yushi.authlibinjector.transform;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class DomainBasedTransformUnit extends LdcTransformUnit {
private static final Pattern URL_REGEX = Pattern.compile("^https?:\\/\\/(?<domain>[^\\/]+)(?<path>\\/.*)$");
private Map<String, String> domainMapping = new ConcurrentHashMap<>();
public Map<String, String> getDomainMapping() {
return domainMapping;
}
@Override
public Optional<String> transformLdc(String input) {
Matcher matcher = URL_REGEX.matcher(input);
if (!matcher.find()) {
return Optional.empty();
}
String domain = matcher.group("domain");
String subdirectory = domainMapping.get(domain);
if (subdirectory == null) {
return Optional.empty();
}
String path = matcher.group("path");
return Optional.of(getApiRoot() + subdirectory + path);
}
protected abstract String getApiRoot();
}

View file

@ -2,18 +2,11 @@ package moe.yushi.authlibinjector.transform;
import static org.objectweb.asm.Opcodes.ASM6;
import java.util.Optional;
import java.util.function.Function;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import moe.yushi.authlibinjector.util.Logging;
public class LdcTransformUnit implements TransformUnit {
private Function<String, Optional<String>> ldcMapper;
public LdcTransformUnit(Function<String, Optional<String>> ldcMapper) {
this.ldcMapper = ldcMapper;
}
public abstract class LdcTransformUnit implements TransformUnit {
@Override
public Optional<ClassVisitor> transform(String className, ClassVisitor writer, Runnable modifiedCallback) {
@ -26,7 +19,7 @@ public class LdcTransformUnit implements TransformUnit {
@Override
public void visitLdcInsn(Object cst) {
if (cst instanceof String) {
Optional<String> transformed = ldcMapper.apply((String) cst);
Optional<String> transformed = transformLdc((String) cst);
if (transformed.isPresent() && !transformed.get().equals(cst)) {
modifiedCallback.run();
Logging.TRANSFORM.fine("Transformed string [" + cst + "] to [" + transformed.get() + "]");
@ -42,4 +35,6 @@ public class LdcTransformUnit implements TransformUnit {
}
});
}
protected abstract Optional<String> transformLdc(String input);
}

View file

@ -1,26 +1,25 @@
package moe.yushi.authlibinjector.transform;
import static java.util.Optional.empty;
import static java.util.Optional.of;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Map;
public class LocalYggdrasilApiTransformUnit extends LdcTransformUnit {
import moe.yushi.authlibinjector.YggdrasilConfiguration;
import moe.yushi.authlibinjector.httpd.LocalYggdrasilHandle;
// ^https?:\/\/(skins\.minecraft\.net)(?<path>\/.*)$
// => <localApiRoot>${path}
public static final Pattern REGEX = Pattern.compile("^https?:\\/\\/(skins\\.minecraft\\.net)(?<path>\\/.*)$");
public class LocalYggdrasilApiTransformUnit extends DomainBasedTransformUnit {
public LocalYggdrasilApiTransformUnit(Supplier<String> localApiRoot) {
super(string -> {
Matcher matcher = REGEX.matcher(string);
if (matcher.find()) {
return of(matcher.replaceAll(localApiRoot.get() + "${path}"));
} else {
return empty();
}
});
private LocalYggdrasilHandle handle;
public LocalYggdrasilApiTransformUnit(YggdrasilConfiguration config) {
handle = new LocalYggdrasilHandle(config);
Map<String, String> mapping = getDomainMapping();
mapping.put("skins.minecraft.net", "skins");
}
@Override
protected String getApiRoot() {
handle.ensureStarted();
return "http://127.0.0.1:" + handle.getLocalApiPort() + "/";
}
@Override

View file

@ -1,12 +0,0 @@
package moe.yushi.authlibinjector.transform;
import java.util.Optional;
import java.util.regex.Pattern;
public class RegexTransformUnit extends LdcTransformUnit {
public RegexTransformUnit(Pattern find, String replace) {
super(input -> Optional.of(find.matcher(input).replaceAll(replace)));
}
}

View file

@ -0,0 +1,28 @@
package moe.yushi.authlibinjector.transform;
import java.util.Map;
public class RemoteYggdrasilTransformUnit extends DomainBasedTransformUnit {
private String apiRoot;
public RemoteYggdrasilTransformUnit(String apiRoot) {
this.apiRoot = apiRoot;
Map<String, String> mapping = getDomainMapping();
mapping.put("api.mojang.com", "api");
mapping.put("authserver.mojang.com", "authserver");
mapping.put("sessionserver.mojang.com", "sessionserver");
mapping.put("skins.minecraft.net", "skins");
}
@Override
protected String getApiRoot() {
return apiRoot;
}
@Override
public String toString() {
return "Yggdrasil API Transformer";
}
}

View file

@ -1,27 +0,0 @@
package moe.yushi.authlibinjector.transform;
import java.util.function.Function;
import java.util.regex.Pattern;
public class YggdrasilApiTransformUnit extends RegexTransformUnit {
// TODO: If java.util.regex supports branch reset, we can use the following regex:
// ^https?:\/\/(?|((?<subdomain>(api|authserver|sessionserver))\.(?<domain>mojang\.com))|((?<subdomain>(skins))\.(?<domain>minecraft\.net)))(?<path>\/.*)$
// => ${apiRoot}${subdomain}${path}
//
// But now it's not supported, so we use a workaround here:
// ^https?:\/\/(?:(?:(api|authserver|sessionserver)\.(mojang\.com))|(?:(skins)\.(minecraft\.net)))(?<path>\/.*)$
// => ${apiRoot}$1$3${path}
public static final Pattern REGEX = Pattern.compile("^https?:\\/\\/(?:(?:(api|authserver|sessionserver)\\.(mojang\\.com))|(?:(skins)\\.(minecraft\\.net)))(?<path>\\/.*)$");
public static final Function<String, String> REPLACEMENT = apiRoot -> apiRoot + "$1$3${path}";
public YggdrasilApiTransformUnit(String apiRoot) {
super(REGEX, REPLACEMENT.apply(apiRoot));
}
@Override
public String toString() {
return "Yggdrasil API Transformer";
}
}

View file

@ -8,7 +8,7 @@ import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import moe.yushi.authlibinjector.transform.YggdrasilApiTransformUnit;
import moe.yushi.authlibinjector.transform.RemoteYggdrasilTransformUnit;
@RunWith(Parameterized.class)
public class UrlReplaceTest {
@ -90,9 +90,8 @@ public class UrlReplaceTest {
@Test
public void test() {
assertEquals(output,
YggdrasilApiTransformUnit.REGEX.matcher(input).replaceAll(
YggdrasilApiTransformUnit.REPLACEMENT.apply(apiRoot)));
RemoteYggdrasilTransformUnit transformer = new RemoteYggdrasilTransformUnit(apiRoot);
assertEquals(output, transformer.transformLdc(input).get());
}
}