allow downloading individual files from bundle

This commit is contained in:
xenofem 2022-05-24 15:14:31 -04:00
parent 43d03869ab
commit 007289ffe5
15 changed files with 499 additions and 69 deletions

View file

@ -1,9 +1,10 @@
mod download;
mod store;
mod timestamp;
mod upload;
mod zip;
use std::{fmt::Debug, fs::File, path::PathBuf, str::FromStr};
use std::{fmt::Debug, path::PathBuf, str::FromStr};
use actix_files::NamedFile;
use actix_web::{
@ -11,11 +12,12 @@ use actix_web::{
HttpServer, Responder,
};
use actix_web_actors::ws;
use askama::Template;
use bytesize::ByteSize;
use log::{error, warn};
use serde::{Deserialize, Serialize};
use store::FileStore;
use tokio::sync::RwLock;
use store::{FileStore, StoredFile};
use tokio::{fs::File, sync::RwLock};
const APP_NAME: &str = "transbeam";
@ -49,9 +51,19 @@ pub fn log_auth_failure(ip_addr: &str) {
warn!("Incorrect authentication attempt from {}", ip_addr);
}
#[derive(Deserialize)]
struct DownloadRequest {
code: String,
download: Option<download::DownloadSelection>,
}
#[derive(Template)]
#[template(path = "download.html")]
struct DownloadInfo<'a> {
file: StoredFile,
code: &'a str,
available: u64,
}
#[get("/download")]
@ -62,29 +74,52 @@ async fn handle_download(
) -> actix_web::Result<HttpResponse> {
let code = &download.code;
if !store::is_valid_storage_code(code) {
return download_not_found(req, data);
return not_found(req, data, true);
}
let info = data.file_store.read().await.lookup_file(code);
if let Some(info) = info {
let storage_path = data.config.storage_dir.join(code);
let file = File::open(&storage_path)?;
let info = if let Some(i) = info {
i
} else {
return not_found(req, data, true)
};
let storage_path = data.config.storage_dir.join(code);
let file = File::open(&storage_path).await?;
if let Some(selection) = download.download {
if let download::DownloadSelection::One(n) = selection {
if let Some(ref files) = info.contents {
if n >= files.len() {
return not_found(req, data, false);
}
} else {
return not_found(req, data, false);
}
}
Ok(download::DownloadingFile {
file,
file: file.into_std().await,
storage_path,
info,
selection,
}
.into_response(&req))
.into_response(&req))
} else {
download_not_found(req, data)
Ok(HttpResponse::Ok().body(DownloadInfo {
file: info,
code,
available: file.metadata().await?.len(),
}.render().unwrap()))
}
}
fn download_not_found(
fn not_found(
req: HttpRequest,
data: web::Data<AppState>,
report: bool,
) -> actix_web::Result<HttpResponse> {
let ip_addr = get_ip_addr(&req, data.config.reverse_proxy);
log_auth_failure(&ip_addr);
if report {
let ip_addr = get_ip_addr(&req, data.config.reverse_proxy);
log_auth_failure(&ip_addr);
}
Ok(NamedFile::open(data.config.static_dir.join("404.html"))?
.set_status_code(StatusCode::NOT_FOUND)
.into_response(&req))