Skip to content
This repository has been archived by the owner on Jan 24, 2022. It is now read-only.

Commit

Permalink
Improve downloading: save to .tmp then rename, check sha1 hash of mav…
Browse files Browse the repository at this point in the history
…en jars
  • Loading branch information
comp500 committed Feb 18, 2020
1 parent bef4e76 commit fb5b89a
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import link.infra.jumploader.resources.MavenJar;
import link.infra.jumploader.resources.MinecraftJar;
import link.infra.jumploader.resources.ParsedArguments;
import link.infra.jumploader.util.RequestJson;
import link.infra.jumploader.util.RequestUtils;

import java.io.IOException;
import java.net.URI;
Expand All @@ -34,7 +34,7 @@ public void updateConfig(ConfigFile configFile, ParsedArguments args, Environmen
String side = configFile.autoconfig.side != null ? configFile.autoconfig.side : args.inferredSide;
try {
URL loaderJsonUrl = new URI("https", "meta.fabricmc.net", "/v2/versions/loader/" + args.mcVersion, null).toURL();
JsonArray manifestData = RequestJson.getJson(loaderJsonUrl).getAsJsonArray();
JsonArray manifestData = RequestUtils.getJson(loaderJsonUrl).getAsJsonArray();
if (manifestData.size() == 0) {
throw new RuntimeException("Failed to update configuration: no Fabric versions available!");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import link.infra.jumploader.util.RequestJson;
import link.infra.jumploader.util.RequestUtils;

import java.io.IOException;
import java.net.URL;
Expand All @@ -21,14 +21,14 @@ private LoginValidationException() {
public static void validate(String accessToken) throws IOException {
JsonObject req = new JsonObject();
req.addProperty("accessToken", accessToken);
int resCode = RequestJson.postJsonForResCode(new URL("https://authserver.mojang.com/validate"), req);
int resCode = RequestUtils.postJsonForResCode(new URL("https://authserver.mojang.com/validate"), req);
if (resCode != 204 && resCode != 200) {
throw new LoginValidationException();
}
}

public static URL retrieveVersionMetaUrl(String minecraftVersion) throws IOException {
JsonObject manifestData = RequestJson.getJson(new URL("https://launchermeta.mojang.com/mc/game/version_manifest.json")).getAsJsonObject();
JsonObject manifestData = RequestUtils.getJson(new URL("https://launchermeta.mojang.com/mc/game/version_manifest.json")).getAsJsonObject();
JsonArray versions = manifestData.getAsJsonArray("versions");
for (JsonElement version : versions) {
JsonObject versionObj = version.getAsJsonObject();
Expand All @@ -47,7 +47,7 @@ private DownloadDetails() {}
}

public static DownloadDetails retrieveDownloadDetails(URL versionMetaUrl, String downloadType) throws IOException {
JsonObject manifestData = RequestJson.getJson(versionMetaUrl).getAsJsonObject();
JsonObject manifestData = RequestUtils.getJson(versionMetaUrl).getAsJsonObject();
JsonObject downloads = manifestData.getAsJsonObject("downloads");
JsonObject download = downloads.getAsJsonObject(downloadType);
Gson gson = new Gson();
Expand Down
25 changes: 24 additions & 1 deletion src/main/java/link/infra/jumploader/resources/MavenJar.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package link.infra.jumploader.resources;

import link.infra.jumploader.DownloadWorkerManager;
import link.infra.jumploader.util.InvalidHashException;
import link.infra.jumploader.util.RequestUtils;
import link.infra.jumploader.util.SHA1HashingInputStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
Expand All @@ -14,6 +20,8 @@ public class MavenJar extends ResolvableJar {
public String mavenPath;
public String repoUrl;

private static final Logger LOGGER = LogManager.getLogger();

public MavenJar(EnvironmentDiscoverer.JarStorageLocation jarStorage) {
super(jarStorage);
}
Expand All @@ -33,11 +41,26 @@ public URL resolveLocal() throws FileNotFoundException {
throw new FileNotFoundException();
}

private static URL getSha1Url(URL downloadUrl) throws MalformedURLException {
return new URL(downloadUrl.getProtocol(), downloadUrl.getHost(), downloadUrl.getPort(), downloadUrl.getFile() + ".sha1");
}

@Override
public URL resolveRemote(DownloadWorkerManager.TaskStatus status, ParsedArguments args) throws URISyntaxException, IOException {
URL downloadUrl = resolveMavenPath(new URI(repoUrl), mavenPath).toURL();
Path jarPath = jarStorage.getMavenJar(mavenPath);
downloadFile(status, downloadUrl, jarPath, is -> is);

String sha1Hash = RequestUtils.getString(getSha1Url(downloadUrl));

try {
downloadFile(status, downloadUrl, jarPath, SHA1HashingInputStream.transformer(sha1Hash));
} catch (InvalidHashException e) {
// TODO: better UI for this?
LOGGER.error("Maven JAR hash mismatch for " + downloadUrl);
LOGGER.error("Expected: " + sha1Hash);
LOGGER.error("Found: " + e.hashFound);
throw new RuntimeException("Failed to download Maven JAR!");
}
return pathToURL(jarPath);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import link.infra.jumploader.DownloadWorkerManager;
import link.infra.jumploader.meta.MinecraftDownloadApi;
import link.infra.jumploader.util.InvalidHashException;
import link.infra.jumploader.util.SHA1HashingInputStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand Down Expand Up @@ -49,12 +50,11 @@ public URL resolveRemote(DownloadWorkerManager.TaskStatus status, ParsedArgument
Path gameJarPath = jarStorage.getGameJar(gameVersion, downloadType);
try {
downloadFile(status, details.url, gameJarPath, SHA1HashingInputStream.transformer(details.sha1));
} catch (SHA1HashingInputStream.InvalidHashException e) {
} catch (InvalidHashException e) {
// TODO: better UI for this?
LOGGER.error("Minecraft JAR hash mismatch for " + details.url);
LOGGER.error("Expected: " + details.sha1);
LOGGER.error("Found: " + e.hashFound);
Files.deleteIfExists(gameJarPath);
throw new RuntimeException("Failed to download Minecraft JAR!");
}
return pathToURL(gameJarPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import link.infra.jumploader.DownloadWorkerManager;
import link.infra.jumploader.Jumploader;
import link.infra.jumploader.util.InvalidHashException;

import javax.annotation.Nonnull;
import java.io.FileNotFoundException;
Expand All @@ -14,6 +15,7 @@
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.function.Function;

public abstract class ResolvableJar {
Expand Down Expand Up @@ -108,9 +110,15 @@ protected static void downloadFile(DownloadWorkerManager.TaskStatus status, URL
conn.setRequestProperty("Accept", "application/octet-stream");

int contentLength = conn.getContentLength();
Path destPathTemp = destPath.resolveSibling(destPath.getFileName() + ".tmp");
try (InputStream res = bytesTransformer.apply(conn.getInputStream());
BytesReportingInputStream bris = new BytesReportingInputStream(res, status, contentLength)) {
Files.copy(bris, destPath);
Files.copy(bris, destPathTemp, StandardCopyOption.REPLACE_EXISTING);
Files.move(destPathTemp, destPath);
} catch (InvalidHashException e) {
Files.deleteIfExists(destPath);
Files.deleteIfExists(destPathTemp);
throw e;
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/main/java/link/infra/jumploader/util/InvalidHashException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package link.infra.jumploader.util;

import java.io.IOException;

public class InvalidHashException extends IOException {
public final String hashFound;

public InvalidHashException(String hashFound) {
this.hashFound = hashFound;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;

public class RequestJson {
private RequestJson() {}
public class RequestUtils {
private RequestUtils() {}

public static JsonElement getJson(URL requestUrl) throws IOException {
URLConnection conn = requestUrl.openConnection();
Expand Down Expand Up @@ -39,4 +40,19 @@ public static int postJsonForResCode(URL requestUrl, JsonElement requestData) th
return conn.getResponseCode();
}

public static String getString(URL requestUrl) throws IOException {
URLConnection conn = requestUrl.openConnection();
conn.setRequestProperty("User-Agent", Jumploader.USER_AGENT);
conn.setRequestProperty("Accept", "text/plain");

ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
try (InputStream res = conn.getInputStream()) {
int n;
while ((n = res.read(buffer, 0, 1024)) != -1) {
baos.write(buffer, 0, n);
}
}
return baos.toString(StandardCharsets.UTF_8.name());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,6 @@ public class SHA1HashingInputStream extends FilterInputStream {
private final byte[] compareToHash;
private final MessageDigest digest;

public static class InvalidHashException extends IOException {
public final String hashFound;

public InvalidHashException(String hashFound) {
this.hashFound = hashFound;
}
}

public static Function<InputStream, InputStream> transformer(String compareToHash) {
return inputStream -> new SHA1HashingInputStream(inputStream, compareToHash);
}
Expand Down

0 comments on commit fb5b89a

Please sign in to comment.