diff options
Diffstat (limited to 'primedev/mods/autodownload/moddownloader.h')
-rw-r--r-- | primedev/mods/autodownload/moddownloader.h | 151 |
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(); +}; |