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",
|
"chrono",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"futures",
|
"futures",
|
||||||
|
"htmlescape",
|
||||||
"log",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
"openssl-sys",
|
"openssl-sys",
|
||||||
|
@ -1078,6 +1079,12 @@ dependencies = [
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "htmlescape"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
|
|
@ -20,6 +20,7 @@ mime = "0.3.16"
|
||||||
rand = "0.7.3"
|
rand = "0.7.3"
|
||||||
chrono = "0.4.13"
|
chrono = "0.4.13"
|
||||||
openssl-sys = "*"
|
openssl-sys = "*"
|
||||||
|
htmlescape = "0.3.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
vendored = ["openssl-sys/vendored"]
|
vendored = ["openssl-sys/vendored"]
|
||||||
|
|
21
src/main.rs
21
src/main.rs
|
@ -97,7 +97,8 @@ async fn download(
|
||||||
.next()
|
.next()
|
||||||
.await
|
.await
|
||||||
.map_err(|_| error::ErrorInternalServerError("could not run select statement"))?
|
.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_id: String = row.get("file_id");
|
||||||
let file_name: String = row.get("file_name");
|
let file_name: String = row.get("file_name");
|
||||||
let kind: String = row.get("kind");
|
let kind: String = row.get("kind");
|
||||||
|
@ -105,12 +106,19 @@ async fn download(
|
||||||
path.push(&file_id);
|
path.push(&file_id);
|
||||||
|
|
||||||
if kind == FileKind::TEXT.to_string() {
|
if kind == FileKind::TEXT.to_string() {
|
||||||
let content = fs::read_to_string(path).await?;
|
let content = fs::read_to_string(path).await.map_err(|_| {
|
||||||
let view_html = VIEW_HTML.replace("{text}", &content);
|
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);
|
let response = HttpResponse::Ok().content_type("text/html").body(view_html);
|
||||||
Ok(response)
|
Ok(response)
|
||||||
} else {
|
} 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,
|
disposition: DispositionType::Attachment,
|
||||||
parameters: vec![DispositionParam::Filename(file_name)],
|
parameters: vec![DispositionParam::Filename(file_name)],
|
||||||
});
|
});
|
||||||
|
@ -121,6 +129,7 @@ async fn download(
|
||||||
async fn setup_db() -> PgPool {
|
async fn setup_db() -> PgPool {
|
||||||
let pool = PgPool::builder()
|
let pool = PgPool::builder()
|
||||||
.max_size(5)
|
.max_size(5)
|
||||||
|
.connect_timeout(std::time::Duration::from_secs(5))
|
||||||
.build(&env::var("DATABASE_URL").unwrap_or_else(|_| "postgresql://localhost".to_owned()))
|
.build(&env::var("DATABASE_URL").unwrap_or_else(|_| "postgresql://localhost".to_owned()))
|
||||||
.await
|
.await
|
||||||
.expect("could not create db pool");
|
.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())),
|
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);
|
let (send, recv) = async_std::sync::channel::<()>(1);
|
||||||
task::spawn(deleter::delete_old_files(
|
task::spawn(deleter::delete_old_files(
|
||||||
recv,
|
recv,
|
||||||
|
|
|
@ -66,6 +66,13 @@ pub(crate) async fn parse_multipart(
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
error::ErrorBadRequest(format!("field validity_secs is not a number: {}", 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 valid_till = Local::now() + Duration::seconds(validity_secs);
|
||||||
let kind = kind.ok_or_else(|| error::ErrorBadRequest("no content found"))?;
|
let kind = kind.ok_or_else(|| error::ErrorBadRequest("no content found"))?;
|
||||||
Ok((original_name, valid_till, kind))
|
Ok((original_name, valid_till, kind))
|
||||||
|
|
|
@ -22,6 +22,10 @@ a:visited {
|
||||||
color: mediumorchid;
|
color: mediumorchid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-right: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
input,
|
input,
|
||||||
select,
|
select,
|
||||||
textarea {
|
textarea {
|
||||||
|
@ -33,6 +37,6 @@ textarea {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type='submit'] {
|
input[type="submit"] {
|
||||||
background-color: green;
|
background-color: green;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
cols="120"
|
cols="120"
|
||||||
></textarea>
|
></textarea>
|
||||||
<br />
|
<br />
|
||||||
Gültig für
|
<label for="validity_secs">Gültig für</label>
|
||||||
<select name="validity_secs">
|
<select id="validity_secs" name="validity_secs">
|
||||||
<option value="1800">30 minuten</option>
|
<option value="1800">30 minuten</option>
|
||||||
<option value="3600">60 minuten</option>
|
<option value="3600">60 minuten</option>
|
||||||
<option value="43200">12 stunden</option>
|
<option value="43200">12 stunden</option>
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
<main>
|
<main>
|
||||||
<h1><a href="/">datatrash</a></h1>
|
<h1><a href="/">datatrash</a></h1>
|
||||||
<p>
|
<p>
|
||||||
Uploaded
|
Datei ist verfügbar unter
|
||||||
<a href="{server}/file/{id}">
|
<a href="{server}/file/{id}">
|
||||||
http://localhost:8000/files/{id}
|
{server}/files/{id}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</main>
|
</main>
|
||||||
|
|
Loading…
Reference in New Issue