db timeout, dont leak inner workings, auto create files dir, fix script injection
This commit is contained in:
parent
f7aa5b7b07
commit
7403abbe99
|
@ -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"
|
||||
|
|
|
@ -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"]
|
||||
|
|
27
src/main.rs
27
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,
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue