package info.mineshafter.intercept;
import info.mineshafter.Util;
import info.mineshafter.crypto.Hash;
import info.mineshafter.http.client.HttpClient;
import info.mineshafter.util.JarPatcher;
import info.mineshafter.util.Resources;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonObject;
import com.eclipsesource.json.JsonValue;
public class MetadataHandler implements Handler {
private static MetadataHandler instance;
private static String METADATA_HOST = "launchermeta.mojang.com";
private static String LIBRARY_HOST = "libraries.minecraft.net";
private static Pattern manifestMatcher = Pattern.compile("/mc/game/[a-fA-F0-9]+/.*\\.json");
private static Map<String, byte[]> artifactCache = new ConcurrentHashMap<String, byte[]>();
public static synchronized MetadataHandler getInstance() {
if (instance == null) {
instance = new MetadataHandler();
}
return instance;
}
private MetadataHandler() {}
public boolean canHandle(URL url) {
String host = url.getHost();
if (host.equalsIgnoreCase(METADATA_HOST)) {
Matcher m = manifestMatcher.matcher(url.getPath());
return m.matches();
} else if (host.equalsIgnoreCase(LIBRARY_HOST)) { return artifactCache.containsKey(url.toString()); }
return false;
}
public Response handle(Request req) {
Matcher m = manifestMatcher.matcher(req.getPath());
if (m.matches()) return handleManifest(req);
String cacheKey = req.getUrl().toString();
if (artifactCache.containsKey(cacheKey)) return handleArtifact(cacheKey);
return null;
}
private Response handleManifest(Request req) {
String authlibUrl = null;
String manifest = new String(HttpClient.getRaw(req.getUrl()));
JsonObject manifestJson = JsonObject.readFrom(manifest);
JsonArray libraries = manifestJson.get("libraries").asArray();
for (JsonValue v : libraries) {
JsonObject lib = v.asObject();
String name = lib.get("name").asString();
if (name.contains("authlib")) {
JsonObject artifact = lib.get("downloads").asObject().get("artifact").asObject();
authlibUrl = artifact.get("url").asString();
byte[] authlibData = HttpClient.getRaw(authlibUrl);
File outputFile = new File(Util.getWorkingDirectory() + File.separator + "libraries" + File.separator + Util.getArtifactPath(name, "jar"));
if (!outputFile.getParentFile().exists()) {
outputFile.getParentFile().mkdirs();
}
patchAuthlib(authlibData, outputFile);
String patchedAuthlibHash = null;
try {
patchedAuthlibHash = Hash.sha1(new FileInputStream(outputFile));
} catch (FileNotFoundException ex) {
System.out.println("Failed to get authlib sha1.");
}
artifact.set("sha1", patchedAuthlibHash);
artifact.set("size", outputFile.length());
break;
}
}
System.out.print("Updated manifest:");
System.out.println(manifestJson.toString());
byte[] manifestData = manifestJson.toString().getBytes();
if (authlibUrl != null) {
artifactCache.put(authlibUrl, manifestData);
}
return new Response(manifestData);
}
private void patchAuthlib(byte[] authlibData, File output) {
JarPatcher patcher = new JarPatcher(authlibData);
patcher.setEntry("com/mojang/authlib/properties/Property.class", Resources.loadByteArray("resources/Property.class"));
patcher.write(output);
}
private Response handleArtifact(String cacheKey) {
return new Response(artifactCache.get(cacheKey));
}
}