downloads work

This commit is contained in:
Brandon Thomas committed 2026-01-04 21:55:16 -05:00
1 parent d9018028ab
commit ba4871118b
1 file changed
+39 -17
@@ -15,46 +15,47 @@ pub async fn download_url_to_user_download_dir(
app_prefs: &AppPreferences,
) -> Result<PathBuf, ArtcraftError> {
let url_path = match url.to_file_path() {
Ok(path) => path,
Err(err) => {
error!("Could not get file path from URL: {:?}", err);
return Err(ArtcraftError::AnyhowError(anyhow!("Could not get file path from URL: {:?}", err)));
}
};
let path_segments = url.path_segments()
.ok_or_else(|| ArtcraftError::AnyhowError(anyhow!("URL does not have path segments (1): {:?}", url)))?;
let url_file_name = url_path
.file_name()
.ok_or(ArtcraftError::AnyhowError(anyhow!(
"No file name for path: {:?} at url: {:?}", &url_path, &url)))?
.to_str()
.ok_or(ArtcraftError::AnyhowError(anyhow!(
"No file name for path: {:?} at url: {:?}", &url_path, &url)))?
let mut url_file_name = path_segments.last()
.ok_or_else(|| ArtcraftError::AnyhowError(anyhow!("URL does not have path segments (2): {:?}", url)))?
.trim()
.to_string();
if !url_file_name.starts_with("artcraft") {
url_file_name = format!("artcraft_{}", url_file_name);
}
let url_file_name = url_file_name;
check_url_file_name_for_downloadability(&url_file_name)?;
let download_directory = app_prefs
.preferred_download_directory
.download_directory(app_data_root);
info!("Pushing path `{}` onto downloaded directory `{:?}`", url_file_name, download_directory);
let download_filename = {
let mut download_filename = download_directory.clone();
download_filename.push(&url_file_name);
download_directory
download_filename
};
info!("Download filename: `{:?}`", download_filename);
if download_filename.exists() {
return Err(ArtcraftError::CannotDownloadFilePathAlreadyExists { path: download_filename }.into());
}
info!("Downloading bytes from url: {:?}", url);
let response = reqwest::get(url.clone()).await?;
let response_bytes = response.bytes().await?;
info!("Writing file: {:?}", download_filename);
let mut file = OpenOptions::new()
.create(true)
.write(true)
@@ -68,6 +69,16 @@ pub async fn download_url_to_user_download_dir(
// TODO: This likely needs more protections.
fn check_url_file_name_for_downloadability(filename: &str) -> Result<(), ArtcraftError> {
if filename.trim().is_empty() {
error!("Download filename is empty!");
return Err(ArtcraftError::BadDownloadFilename { path: "".into() }.into());
}
if !filename.is_ascii() {
error!("Download filename is not completely ASCII: {:?}", filename);
return Err(ArtcraftError::BadDownloadFilename { path: filename.into() }.into());
}
if filename.contains("/")
|| filename.contains("..")
|| filename.contains("\\")
@@ -76,6 +87,17 @@ fn check_url_file_name_for_downloadability(filename: &str) -> Result<(), Artcraf
return Err(ArtcraftError::BadDownloadFilename { path: filename.into() }.into());
}
if filename.contains("'")
|| filename.contains("\"")
|| filename.contains("%")
|| filename.contains("<")
|| filename.contains(">")
|| filename.contains("|")
{
error!("Download filename has dangerous path components: {:?}", filename);
return Err(ArtcraftError::BadDownloadFilename { path: filename.into() }.into());
}
if filename.ends_with("apk")
|| filename.ends_with("app")
|| filename.ends_with("bat")