db timeout, dont leak inner workings, auto create files dir, fix script injection

This commit is contained in:
neri 2020-07-13 15:22:33 +02:00
parent f7aa5b7b07
commit 7403abbe99
7 changed files with 44 additions and 12 deletions

7
Cargo.lock generated
View File

@ -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"

View File

@ -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"]

View File

@ -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,12 +106,19 @@ 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 {
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)],
});
@ -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,

View File

@ -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))

View File

@ -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;
}

View File

@ -18,8 +18,8 @@
cols="120"
></textarea>
<br />
Gültig für
<select name="validity_secs">
<label for="validity_secs">Gültig für</label>
<select id="validity_secs" name="validity_secs">
<option value="1800">30 minuten</option>
<option value="3600">60 minuten</option>
<option value="43200">12 stunden</option>

View File

@ -9,9 +9,9 @@
<main>
<h1><a href="/">datatrash</a></h1>
<p>
Uploaded
Datei ist verfügbar unter
<a href="{server}/file/{id}">
http://localhost:8000/files/{id}
{server}/files/{id}
</a>
</p>
</main>