diff --git a/src-tauri/src/launcher/manifest.rs b/src-tauri/src/launcher/manifest.rs index 57cd15f..f064584 100644 --- a/src-tauri/src/launcher/manifest.rs +++ b/src-tauri/src/launcher/manifest.rs @@ -69,7 +69,7 @@ pub struct Library { #[derive(Serialize, Deserialize)] pub struct LibraryDownload { - artifact: LibraryArtifact + pub artifact: LibraryArtifact } #[derive(Serialize, Deserialize)] @@ -93,11 +93,11 @@ pub enum OSName { } #[derive(Serialize, Deserialize)] -struct LibraryArtifact { - path: String, - sha1: String, - size: i64, - url: String, +pub struct LibraryArtifact { + pub path: String, + pub sha1: String, + pub size: i64, + pub url: String, } pub async fn get_version_detail(reqwest: &Client, version : &Version) -> Result { diff --git a/src-tauri/src/launcher/mod.rs b/src-tauri/src/launcher/mod.rs index ea391d9..b794c4b 100644 --- a/src-tauri/src/launcher/mod.rs +++ b/src-tauri/src/launcher/mod.rs @@ -1,11 +1,13 @@ mod manifest; -use std::path::Path; +use std::path::{Path, self}; -use anyhow::Result; +use anyhow::{Result, bail}; use reqwest::Client; use serde::{Serialize, Deserialize}; -use tokio::fs; +use tokio::{fs, io::AsyncWriteExt}; + +use crate::authentification::GameProfile; use self::manifest::{VersionDetail, get_version_manifest, get_version_from_manifest, get_version_detail, Library, OSName}; @@ -18,6 +20,7 @@ const ACTUAL_OS: OSName = OSName::Linux; const ACTUAL_OS: OSName = OSName::MacOsX; pub struct ClientOptions<'a> { + pub authorization: GameProfile, pub root_path: &'a Path, pub java_path: &'a Path, pub version_number: String, @@ -57,11 +60,41 @@ impl<'a> MinecraftClient<'_> { if !self.opts.root_path.exists() { fs::create_dir_all(self.opts.root_path).await?; } - let lib = self.opts.root_path.join("librairies"); + let lib = &self.opts.root_path.join("libraries"); if !lib.exists() { fs::create_dir(lib).await?; } self.filter_non_necessary_librairies(); + for (_, i) in self.details.libraries.iter().enumerate() { + let p = i.downloads.artifact.path.clone(); + let mut splited = p.split("/").collect::>(); + splited.pop(); // remove last element + let p = splited.join(path::MAIN_SEPARATOR_STR); + let p = &lib.join(p); + fs::create_dir_all(p).await?; + let url = i.downloads.artifact.url.clone(); + let mut sha = url.clone(); + sha.push_str(".sha1"); + + let sha1 = self.reqwest_client + .get(sha) + .send() + .await? + .text() + .await?; + if sha1 != i.downloads.artifact.sha1 { + bail!("Sha1 hash of a library is invalid, a malicious file might be present on the remote server") + } + let content = self.reqwest_client + .get(url) + .send() + .await? + .bytes() + .await?; + let mut file = fs::File::create(p).await?; + file.write_all(&content).await?; + println!("{} downloaded", i.name); + } Ok(()) } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index f3a6542..086fac4 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -9,7 +9,7 @@ pub mod launcher; use std::sync::Mutex; use authentification::{Authentification, Prompt, GameProfile}; -use anyhow::{Result, bail}; +use anyhow::Result; use directories::BaseDirs; use launcher::{MinecraftClient, ClientOptions}; @@ -51,7 +51,11 @@ async fn download(state: tauri::State<'_, Mutex>) -> Result Ok(res.0.clone()), Err(err) => Err(err.to_string()) }?; + if game_profile.is_none() { + return Err("You're not connected".to_string()); + } let opts = ClientOptions { + authorization: game_profile.unwrap(), root_path, java_path: &java_path.as_path(), version_number: "1.19.4".to_string(),