Feat[modpacks]: verify mod sha1

This commit is contained in:
Mathias-Boulay 2023-11-21 18:18:04 +01:00 committed by Maksim Belov
parent 30541c2e3c
commit d52559ab93
3 changed files with 49 additions and 9 deletions

View File

@ -2,6 +2,8 @@ package net.kdt.pojavlaunch.modloaders.modpacks.api;
import android.util.Log;
import androidx.annotation.Nullable;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@ -181,7 +183,7 @@ public class CurseforgeApi implements ModpackApi{
if(url == null && curseFile.required)
throw new IOException("Failed to obtain download URL for "+curseFile.projectID+" "+curseFile.fileID);
else if(url == null) return null;
return new ModDownloader.FileInfo(url, FileUtils.getFileName(url));
return new ModDownloader.FileInfo(url, FileUtils.getFileName(url), getDownloadSha1(curseFile.projectID, curseFile.fileID));
});
}
modDownloader.awaitFinish((c,m)->
@ -240,6 +242,23 @@ public class CurseforgeApi implements ModpackApi{
return null;
}
private @Nullable String getDownloadSha1(long projectID, long fileID) {
// Try the api endpoint, die in the other case
JsonObject response = mApiHandler.get("mods/"+projectID+"/files/"+fileID, JsonObject.class);
if (response == null || response.get("data").isJsonNull()) return null;
JsonArray hashes = response.get("data").getAsJsonObject().getAsJsonArray("hashes");
for (JsonElement jsonElement : hashes) {
// The sha1 = 1; md5 = 2;
if(jsonElement.getAsJsonObject().get("algo").getAsInt() == ALGO_SHA_1){
return jsonElement.getAsJsonObject().get("value").getAsString();
}
}
// No hashes available
return null;
}
private boolean verifyManifest(CurseManifest manifest) {
if(!"minecraftModpack".equals(manifest.manifestType)) return false;
if(manifest.manifestVersion != 1) return false;

View File

@ -1,5 +1,7 @@
package net.kdt.pojavlaunch.modloaders.modpacks.api;
import androidx.annotation.Nullable;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.utils.DownloadUtils;
@ -34,10 +36,10 @@ public class ModDownloader {
this.mUseFileCount = useFileCount;
}
public void submitDownload(int fileSize, String relativePath, String... url) {
public void submitDownload(int fileSize, String relativePath, @Nullable String downloadHash, String... url) {
if(mUseFileCount) mTotalSize += 1;
else mTotalSize += fileSize;
mDownloadPool.execute(new DownloadTask(url, new File(mDestinationDirectory, relativePath)));
mDownloadPool.execute(new DownloadTask(url, new File(mDestinationDirectory, relativePath), downloadHash));
}
public void submitDownload(FileInfoProvider infoProvider) {
@ -93,7 +95,7 @@ public class ModDownloader {
FileInfo fileInfo = mFileInfoProvider.getFileInfo();
if(fileInfo == null) return;
new DownloadTask(new String[]{fileInfo.url},
new File(mDestinationDirectory, fileInfo.relativePath)).run();
new File(mDestinationDirectory, fileInfo.relativePath), fileInfo.sha1).run();
}catch (IOException e) {
downloadFailed(e);
}
@ -103,12 +105,14 @@ public class ModDownloader {
class DownloadTask implements Runnable, Tools.DownloaderFeedback {
private final String[] mDownloadUrls;
private final File mDestination;
private final String mSha1;
private int last = 0;
public DownloadTask(String[] downloadurls,
File downloadDestination) {
File downloadDestination, String downloadHash) {
this.mDownloadUrls = downloadurls;
this.mDestination = downloadDestination;
this.mSha1 = downloadHash;
}
@Override
@ -116,8 +120,23 @@ public class ModDownloader {
IOException exception = null;
for(String sourceUrl : mDownloadUrls) {
try {
exception = tryDownload(sourceUrl);
if(exception == null) return;
int i=0;
while (i < 5){
exception = tryDownload(sourceUrl);
if(exception == null) {
if(mSha1 != null && !Tools.compareSHA1(mDestination, mSha1)){
// Remove the target file and retry
i++;
mDestination.delete();
continue;
}
// No Sha or it matched
break;
}
// If there is an exception, try another source
break;
}
}catch (InterruptedException e) {
return;
}
@ -159,10 +178,12 @@ public class ModDownloader {
public static class FileInfo {
public final String url;
public final String relativePath;
public final String sha1;
public FileInfo(String url, String relativePath) {
public FileInfo(String url, String relativePath, @Nullable String sha1) {
this.url = url;
this.relativePath = relativePath;
this.sha1 = sha1;
}
}

View File

@ -125,7 +125,7 @@ public class ModrinthApi implements ModpackApi{
ModDownloader modDownloader = new ModDownloader(instanceDestination);
for(ModrinthIndex.ModrinthIndexFile indexFile : modrinthIndex.files) {
modDownloader.submitDownload(indexFile.fileSize, indexFile.path, indexFile.downloads);
modDownloader.submitDownload(indexFile.fileSize, indexFile.path, indexFile.hashes.sha1, indexFile.downloads);
}
modDownloader.awaitFinish(new DownloaderProgressWrapper(R.string.modpack_download_downloading_mods, ProgressLayout.INSTALL_MODPACK));
ProgressLayout.setProgress(ProgressLayout.INSTALL_MODPACK, 0, R.string.modpack_download_applying_overrides, 1, 2);