diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModDownloader.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModDownloader.java index 3b15a2364..f9eb7ee71 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModDownloader.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModDownloader.java @@ -122,16 +122,14 @@ public class ModDownloader { try { DownloadUtils.ensureSha1(mDestination, mSha1, (Callable) () -> { IOException exception = tryDownload(sourceUrl); - if(exception != null) { - downloadFailed(exception); + throw exception; } - return null; }); }catch (IOException e) { - return; + downloadFailed(e); } } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModpackInstaller.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModpackInstaller.java index 1851b6c27..49b1f6f2f 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModpackInstaller.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModpackInstaller.java @@ -18,7 +18,7 @@ import java.util.concurrent.Callable; public class ModpackInstaller { - public static ModLoader installModpack(ModDetail modDetail, int selectedVersion, InstallFunction installFunction) throws IOException{ + public static ModLoader installModpack(ModDetail modDetail, int selectedVersion, InstallFunction installFunction) throws IOException { String versionUrl = modDetail.versionUrls[selectedVersion]; String versionHash = modDetail.versionHashes[selectedVersion]; String modpackName = modDetail.title.toLowerCase(Locale.ROOT).trim().replace(" ", "_" ); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/NewMinecraftDownloader.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/NewMinecraftDownloader.java index 1998176d2..ba9d4da9c 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/NewMinecraftDownloader.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/NewMinecraftDownloader.java @@ -16,6 +16,7 @@ import net.kdt.pojavlaunch.JRE17Util; import net.kdt.pojavlaunch.R; import net.kdt.pojavlaunch.Tools; import net.kdt.pojavlaunch.mirrors.DownloadMirror; +import net.kdt.pojavlaunch.mirrors.MirrorTamperedException; import net.kdt.pojavlaunch.prefs.LauncherPreferences; import net.kdt.pojavlaunch.utils.DownloadUtils; import net.kdt.pojavlaunch.utils.FileUtils; @@ -34,7 +35,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; -// TODO: implement mirror tamper checking. public class NewMinecraftDownloader { public static final String MINECRAFT_RES = "https://resources.download.minecraft.net/"; private AtomicReference mThrownDownloaderException; @@ -123,17 +123,22 @@ public class NewMinecraftDownloader { return new File(Tools.DIR_HOME_VERSION, versionId + File.separator + versionId + ".jar"); } - private File downloadGameJson(JMinecraftVersionList.Version verInfo) throws IOException { + private File downloadGameJson(JMinecraftVersionList.Version verInfo) throws IOException, MirrorTamperedException { File targetFile = createGameJsonPath(verInfo.id); if(verInfo.sha1 == null && targetFile.canRead() && targetFile.isFile()) return targetFile; FileUtils.ensureParentDirectory(targetFile); - DownloadUtils.ensureSha1(targetFile, LauncherPreferences.PREF_VERIFY_MANIFEST ? verInfo.sha1 : null, ()-> { - ProgressLayout.setProgress(ProgressLayout.DOWNLOAD_MINECRAFT, 0, - R.string.newdl_downloading_metadata, targetFile.getName()); - DownloadMirror.downloadFileMirrored(DownloadMirror.DOWNLOAD_CLASS_METADATA, verInfo.url, targetFile); - return null; - }); + try { + DownloadUtils.ensureSha1(targetFile, LauncherPreferences.PREF_VERIFY_MANIFEST ? verInfo.sha1 : null, () -> { + ProgressLayout.setProgress(ProgressLayout.DOWNLOAD_MINECRAFT, 0, + R.string.newdl_downloading_metadata, targetFile.getName()); + DownloadMirror.downloadFileMirrored(DownloadMirror.DOWNLOAD_CLASS_METADATA, verInfo.url, targetFile); + return null; + }); + }catch (DownloadUtils.SHA1VerificationException e) { + if(DownloadMirror.isMirrored()) throw new MirrorTamperedException(); + else throw e; + } return targetFile; } @@ -166,7 +171,7 @@ public class NewMinecraftDownloader { * @return false if JRE17 installation failed, true otherwise * @throws IOException if the download of any of the metadata files fails */ - private boolean downloadAndProcessMetadata(Activity activity, JMinecraftVersionList.Version verInfo, String versionName) throws IOException { + private boolean downloadAndProcessMetadata(Activity activity, JMinecraftVersionList.Version verInfo, String versionName) throws IOException, MirrorTamperedException { File versionJsonFile; if(verInfo != null) versionJsonFile = downloadGameJson(verInfo); else versionJsonFile = createGameJsonPath(versionName); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/DownloadUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/DownloadUtils.java index 0e281975d..367b415d1 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/DownloadUtils.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/DownloadUtils.java @@ -120,33 +120,35 @@ public class DownloadUtils { return parseResult; } + private static T downloadFile(Callable downloadFunction) throws IOException{ + try { + return downloadFunction.call(); + } catch (IOException e){ + throw e; + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static boolean verifyFile(File file, String sha1) { + return file.exists() && Tools.compareSHA1(file, sha1); + } + public static T ensureSha1(File outputFile, @Nullable String sha1, Callable downloadFunction) throws IOException { // Skip if needed - if(sha1 == null){ - try { - return downloadFunction.call(); - } catch (IOException e){ - throw e; - } - catch (Exception e) { - throw new RuntimeException(e); - } - } + if(sha1 == null) return downloadFile(downloadFunction); int attempts = 0; + boolean fileOkay = verifyFile(outputFile, sha1); T result = null; - while (attempts < 5 && (!outputFile.exists() || !Tools.compareSHA1(outputFile, sha1))){ + while (attempts < 5 && !fileOkay){ attempts++; - try { - result = downloadFunction.call(); - } catch (IOException e){ - throw e; - } catch (Exception e) { - throw new RuntimeException(e); - } + downloadFile(downloadFunction); + fileOkay = verifyFile(outputFile, sha1); } + if(!fileOkay) throw new SHA1VerificationException("SHA1 verifcation failed after 5 download attempts"); return result; - } public interface ParseCallback { @@ -157,5 +159,11 @@ public class DownloadUtils { super(e); } } + + public static class SHA1VerificationException extends IOException { + public SHA1VerificationException(String message) { + super(message); + } + } }