From 7403abbe996998a633e4383302837b24434519ff Mon Sep 17 00:00:00 2001 From: neri Date: Mon, 13 Jul 2020 15:22:33 +0200 Subject: [PATCH] db timeout, dont leak inner workings, auto create files dir, fix script injection --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + src/main.rs | 27 ++++++++++++++++++++------- src/multipart.rs | 7 +++++++ static/index.css | 6 +++++- template/index.html | 4 ++-- template/upload.html | 4 ++-- 7 files changed, 44 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3e7e4f4..39a45e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -686,6 +686,7 @@ dependencies = [ "chrono", "env_logger", "futures", + "htmlescape", "log", "mime", "openssl-sys", @@ -1078,6 +1079,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "htmlescape" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" + [[package]] name = "http" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 0488f7c..a8a3a92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ mime = "0.3.16" rand = "0.7.3" chrono = "0.4.13" openssl-sys = "*" +htmlescape = "0.3.1" [features] vendored = ["openssl-sys/vendored"] diff --git a/src/main.rs b/src/main.rs index 253525a..2cd9293 100644 --- a/src/main.rs +++ b/src/main.rs @@ -97,7 +97,8 @@ async fn download( .next() .await .map_err(|_| error::ErrorInternalServerError("could not run select statement"))? - .ok_or_else(|| error::ErrorNotFound("could not find file"))?; + .ok_or_else(|| error::ErrorNotFound("file does not exist or has expired"))?; + let file_id: String = row.get("file_id"); let file_name: String = row.get("file_name"); let kind: String = row.get("kind"); @@ -105,15 +106,22 @@ async fn download( path.push(&file_id); if kind == FileKind::TEXT.to_string() { - let content = fs::read_to_string(path).await?; - let view_html = VIEW_HTML.replace("{text}", &content); + let content = fs::read_to_string(path).await.map_err(|_| { + error::ErrorInternalServerError("this file should be here but could not be found") + })?; + let encoded = htmlescape::encode_minimal(&content); + let view_html = VIEW_HTML.replace("{text}", &encoded); let response = HttpResponse::Ok().content_type("text/html").body(view_html); Ok(response) } else { - let file = NamedFile::open(path)?.set_content_disposition(ContentDisposition { - disposition: DispositionType::Attachment, - parameters: vec![DispositionParam::Filename(file_name)], - }); + let file = NamedFile::open(path) + .map_err(|_| { + error::ErrorInternalServerError("this file should be here but could not be found") + })? + .set_content_disposition(ContentDisposition { + disposition: DispositionType::Attachment, + parameters: vec![DispositionParam::Filename(file_name)], + }); file.into_response(&req) } } @@ -121,6 +129,7 @@ async fn download( async fn setup_db() -> PgPool { let pool = PgPool::builder() .max_size(5) + .connect_timeout(std::time::Duration::from_secs(5)) .build(&env::var("DATABASE_URL").unwrap_or_else(|_| "postgresql://localhost".to_owned())) .await .expect("could not create db pool"); @@ -153,6 +162,10 @@ async fn main() -> std::io::Result<()> { files_dir: PathBuf::from(env::var("FILES_DIR").unwrap_or_else(|_| "./files".to_owned())), }; + fs::create_dir_all(&config.files_dir) + .await + .expect("could not create directory for storing files"); + let (send, recv) = async_std::sync::channel::<()>(1); task::spawn(deleter::delete_old_files( recv, diff --git a/src/multipart.rs b/src/multipart.rs index 6624195..63e7ecb 100644 --- a/src/multipart.rs +++ b/src/multipart.rs @@ -66,6 +66,13 @@ pub(crate) async fn parse_multipart( .map_err(|e| { error::ErrorBadRequest(format!("field validity_secs is not a number: {}", e)) })?; + let max_validity_secs = Duration::days(31).num_seconds(); + if validity_secs > max_validity_secs { + return Err(error::ErrorBadRequest(format!( + "maximum allowed validity is {} seconds, but you specified {} seconds", + max_validity_secs, validity_secs + ))); + } let valid_till = Local::now() + Duration::seconds(validity_secs); let kind = kind.ok_or_else(|| error::ErrorBadRequest("no content found"))?; Ok((original_name, valid_till, kind)) diff --git a/static/index.css b/static/index.css index 6f24b1f..f47a2ad 100644 --- a/static/index.css +++ b/static/index.css @@ -22,6 +22,10 @@ a:visited { color: mediumorchid; } +label { + margin-right: 0.25em; +} + input, select, textarea { @@ -33,6 +37,6 @@ textarea { margin-bottom: 1rem; } -input[type='submit'] { +input[type="submit"] { background-color: green; } diff --git a/template/index.html b/template/index.html index e09c383..0d08b09 100644 --- a/template/index.html +++ b/template/index.html @@ -18,8 +18,8 @@ cols="120" >
- Gültig für - diff --git a/template/upload.html b/template/upload.html index bacfd6c..1ea3a20 100644 --- a/template/upload.html +++ b/template/upload.html @@ -9,9 +9,9 @@

datatrash

- Uploaded + Datei ist verfügbar unter - http://localhost:8000/files/{id} + {server}/files/{id}