aboutsummaryrefslogtreecommitdiff
path: root/primedev/mods/autodownload/moddownloader.h
diff options
context:
space:
mode:
Diffstat (limited to 'primedev/mods/autodownload/moddownloader.h')
-rw-r--r--primedev/mods/autodownload/moddownloader.h151
1 files changed, 151 insertions, 0 deletions
diff --git a/primedev/mods/autodownload/moddownloader.h b/primedev/mods/autodownload/moddownloader.h
new file mode 100644
index 00000000..5302c21e
--- /dev/null
+++ b/primedev/mods/autodownload/moddownloader.h
@@ -0,0 +1,151 @@
+class ModDownloader
+{
+private:
+ const char* VERIFICATION_FLAG = "-disablemodverification";
+ const char* CUSTOM_MODS_URL_FLAG = "-customverifiedurl=";
+ const char* STORE_URL = "https://gcdn.thunderstore.io/live/repository/packages/";
+ const char* DEFAULT_MODS_LIST_URL = "https://raw.githubusercontent.com/R2Northstar/VerifiedMods/master/verified-mods.json";
+ char* modsListUrl;
+
+ struct VerifiedModVersion
+ {
+ std::string checksum;
+ };
+ struct VerifiedModDetails
+ {
+ std::string dependencyPrefix;
+ std::unordered_map<std::string, VerifiedModVersion> versions = {};
+ };
+ std::unordered_map<std::string, VerifiedModDetails> verifiedMods = {};
+
+ /**
+ * Mod archive download callback.
+ *
+ * This function is called by curl as it's downloading the mod archive; this
+ * will retrieve the current `ModDownloader` instance and update its `modState`
+ * member accordingly.
+ */
+ static int ModFetchingProgressCallback(
+ void* ptr, curl_off_t totalDownloadSize, curl_off_t finishedDownloadSize, curl_off_t totalToUpload, curl_off_t nowUploaded);
+
+ /**
+ * Downloads a mod archive from distant store.
+ *
+ * This rebuilds the URI of the mod archive using both a predefined store URI
+ * and the mod dependency string from the `verifiedMods` variable, or using
+ * input mod name as mod dependency string if bypass flag is set up; fetched
+ * archive is then stored in a temporary location.
+ *
+ * If something went wrong during archive download, this will return an empty
+ * optional object.
+ *
+ * @param modName name of the mod to be downloaded
+ * @param modVersion version of the mod to be downloaded
+ * @returns location of the downloaded archive
+ */
+ std::optional<fs::path> FetchModFromDistantStore(std::string_view modName, std::string_view modVersion);
+
+ /**
+ * Tells if a mod archive has not been corrupted.
+ *
+ * The mod validation procedure includes computing the SHA256 hash of the final
+ * archive, which is stored in the verified mods list. This hash is used by this
+ * very method to ensure the archive downloaded from the Internet is the exact
+ * same that has been manually verified.
+ *
+ * @param modPath path of the archive to check
+ * @param expectedChecksum checksum the archive should have
+ * @returns whether archive is legit
+ */
+ bool IsModLegit(fs::path modPath, std::string_view expectedChecksum);
+
+ /**
+ * Extracts a mod archive to the game folder.
+ *
+ * This extracts a downloaded mod archive from its original location to the
+ * current game profile, in the remote mods folder.
+ *
+ * @param modPath location of the downloaded archive
+ * @returns nothing
+ */
+ void ExtractMod(fs::path modPath);
+
+public:
+ ModDownloader();
+
+ /**
+ * Retrieves the verified mods list from the central authority.
+ *
+ * The Northstar auto-downloading feature does NOT allow automatically installing
+ * all mods for various (notably security) reasons; mods that are candidate to
+ * auto-downloading are rather listed on a GitHub repository
+ * (https://raw.githubusercontent.com/R2Northstar/VerifiedMods/master/verified-mods.json),
+ * which this method gets via a HTTP call to load into local state.
+ *
+ * If list fetching fails, local mods list will be initialized as empty, thus
+ * preventing any mod from being auto-downloaded.
+ *
+ * @returns nothing
+ */
+ void FetchModsListFromAPI();
+
+ /**
+ * Checks whether a mod is verified.
+ *
+ * A mod is deemed verified/authorized through a manual validation process that is
+ * described here: https://github.com/R2Northstar/VerifiedMods; in practice, a mod
+ * is considered authorized if their name AND exact version appear in the
+ * `verifiedMods` variable.
+ *
+ * @param modName name of the mod to be checked
+ * @param modVersion version of the mod to be checked, must follow semantic versioning
+ * @returns whether the mod is authorized and can be auto-downloaded
+ */
+ bool IsModAuthorized(std::string_view modName, std::string_view modVersion);
+
+ /**
+ * Downloads a given mod from Thunderstore API to local game profile.
+ *
+ * @param modName name of the mod to be downloaded
+ * @param modVersion version of the mod to be downloaded
+ * @returns nothing
+ **/
+ void DownloadMod(std::string modName, std::string modVersion);
+
+ enum ModInstallState
+ {
+ // Normal installation process
+ DOWNLOADING,
+ CHECKSUMING,
+ EXTRACTING,
+ DONE, // Everything went great, mod can be used in-game
+
+ // Errors
+ FAILED, // Generic error message, should be avoided as much as possible
+ FAILED_READING_ARCHIVE,
+ FAILED_WRITING_TO_DISK,
+ MOD_FETCHING_FAILED,
+ MOD_CORRUPTED, // Downloaded archive checksum does not match verified hash
+ NO_DISK_SPACE_AVAILABLE,
+ NOT_FOUND // Mod is not currently being auto-downloaded
+ };
+
+ struct MOD_STATE
+ {
+ ModInstallState state;
+ int progress;
+ int total;
+ float ratio;
+ } modState = {};
+
+ /**
+ * Cancels installation of the mod.
+ *
+ * Prevents installation of the mod currently being installed, no matter the install
+ * progress (downloading, checksuming, extracting), and frees all resources currently
+ * being used in this purpose.
+ *
+ * @returns nothing
+ */
+ void CancelDownload();
+};