diff --git a/README.md b/README.md
index af22160..f709403 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
A file and text uploading service with configurable time limit
-![Application screenshot](./screenshot.png)
+![Application screenshot showing the web form for file or text upload](./screenshot.png)
## running
@@ -28,6 +28,7 @@ To run the software directly, use the compiling instructions below.
| RATE_LIMIT_PROXIED | false | whether rate limit should read x-forwarded-for |
| RATE_LIMIT_REPLENISH_SECONDS | 60 | seconds to wait between requests |
| RATE_LIMIT_BURST | 480 | allowed request burst |
+| ABUSE_MAIL | | email address to report abuse to |
### Database configuration
diff --git a/snippet/abuse.html.snippet b/snippet/abuse.html.snippet
new file mode 100644
index 0000000..29dda37
--- /dev/null
+++ b/snippet/abuse.html.snippet
@@ -0,0 +1,6 @@
+
+
+ inhalt melden
+
diff --git a/src/config.rs b/src/config.rs
index 7029129..7953b9e 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -16,6 +16,7 @@ pub struct Config {
pub proxied: bool,
pub rate_limit_replenish_seconds: u64,
pub rate_limit_burst: u32,
+ pub abuse_mail: Option,
}
#[derive(Clone)]
@@ -53,6 +54,7 @@ pub async fn from_env() -> Config {
.ok()
.and_then(|burst| burst.parse().ok())
.unwrap_or(480);
+ let abuse_mail = env::var("ABUSE_MAIL").ok();
Config {
static_dir,
@@ -63,6 +65,7 @@ pub async fn from_env() -> Config {
proxied,
rate_limit_replenish_seconds,
rate_limit_burst,
+ abuse_mail,
}
}
diff --git a/src/download.rs b/src/download.rs
index 58495e4..e3bc828 100644
--- a/src/download.rs
+++ b/src/download.rs
@@ -17,7 +17,7 @@ use time::OffsetDateTime;
use tokio::fs;
use url::Url;
-use crate::{config::Config, deleter, mime_relations};
+use crate::{config::Config, deleter, mime_relations, template};
const TEXT_VIEW_HTML: &str = include_str!("../template/text-view.html");
const URL_VIEW_HTML: &str = include_str!("../template/url-view.html");
@@ -43,7 +43,7 @@ pub async fn download(
let mut response = match get_view_type(&req, &mime, &path, delete).await {
ViewType::Raw => build_file_response(false, &file_name, path, mime, &req),
ViewType::Download => build_file_response(true, &file_name, path, mime, &req),
- ViewType::Html => build_html_response(&path).await,
+ ViewType::Html => build_html_response(&path, &config, &req).await,
}?;
insert_cache_headers(&mut response, valid_till);
@@ -121,20 +121,26 @@ async fn get_file_size(file_path: &Path) -> u64 {
.unwrap_or(0)
}
-async fn build_html_response(path: &Path) -> Result {
+async fn build_html_response(
+ path: &Path,
+ config: &Config,
+ req: &HttpRequest,
+) -> Result {
let content = fs::read_to_string(path).await.map_err(|file_err| {
log::error!("file could not be read {:?}", file_err);
error::ErrorInternalServerError("this file should be here but could not be found")
})?;
let encoded = htmlescape::encode_minimal(&content);
- let html = if !content.trim().contains(['\n', '\r']) && Url::from_str(content.trim()).is_ok() {
- let attribute_encoded = htmlescape::encode_attribute(&content);
- URL_VIEW_HTML
- .replace("{link_content}", &encoded)
- .replace("{link_attribute}", &attribute_encoded)
- } else {
- TEXT_VIEW_HTML.replace("{text}", &encoded)
- };
+ let mut html =
+ if !content.trim().contains(['\n', '\r']) && Url::from_str(content.trim()).is_ok() {
+ let attribute_encoded = htmlescape::encode_attribute(&content);
+ URL_VIEW_HTML
+ .replace("{link_content}", &encoded)
+ .replace("{link_attribute}", &attribute_encoded)
+ } else {
+ TEXT_VIEW_HTML.replace("{text}", &encoded)
+ };
+ html = template::insert_abuse_template(html, Some(req), config);
Ok(HttpResponse::Ok()
.content_type(TEXT_HTML.to_string())
.body(html))
diff --git a/src/template.rs b/src/template.rs
index 25b9edf..2708418 100644
--- a/src/template.rs
+++ b/src/template.rs
@@ -10,6 +10,7 @@ const INDEX_HTML: &str = include_str!("../template/index.html");
const AUTH_HIDE_JS: &str = include_str!("../template/auth-hide.js");
const AUTH_SNIPPET_HTML: &str = include_str!("../snippet/auth.html.snippet");
const MAX_SIZE_SNIPPET_HTML: &str = include_str!("../snippet/max_size.html.snippet");
+const ABUSE_SNIPPET_HTML: &str = include_str!("../snippet/abuse.html.snippet");
pub async fn write_prefillable_templates(config: &Config) {
let index_path = config.static_dir.join("index.html");
@@ -47,6 +48,7 @@ fn build_index_html(config: &Config) -> String {
} else {
html = html.replace("{auth_snippet}", "");
}
+ html = insert_abuse_template(html, None, config);
if let Some(max_file_size) = config.max_file_size {
html = html
.replace("{max_size_snippet}", MAX_SIZE_SNIPPET_HTML.trim_end())
@@ -57,6 +59,22 @@ fn build_index_html(config: &Config) -> String {
html
}
+pub fn insert_abuse_template(html: String, req: Option<&HttpRequest>, config: &Config) -> String {
+ if let Some(abuse_mail) = &config.abuse_mail {
+ let url = if let Some(req) = req {
+ format!("{host}{path}", host = get_host_url(req), path = req.uri())
+ } else {
+ String::new()
+ };
+ // urlencoding::encode(data)
+ html.replace("{abuse}", ABUSE_SNIPPET_HTML.trim_end())
+ .replace("{abusemail}", abuse_mail)
+ .replace("{url}", &urlencoding::encode(&url))
+ } else {
+ html.replace("{abuse}", "")
+ }
+}
+
fn render_file_size(size: u64) -> String {
let magnitude = cmp::min((size as f64).log(1024.0) as u32, 5);
let prefix = ["", "ki", "Mi", "Gi", "Ti", "Pi"][magnitude as usize];
diff --git a/src/upload.rs b/src/upload.rs
index 490bdc5..a25f250 100644
--- a/src/upload.rs
+++ b/src/upload.rs
@@ -144,7 +144,7 @@ fn get_redirect_url(id: &str, name: Option<&str>) -> String {
}
}
-pub async fn uploaded(req: HttpRequest) -> Result {
+pub async fn uploaded(req: HttpRequest, config: web::Data) -> Result {
let id = req.match_info().query("id");
let name = req
.match_info()
@@ -152,13 +152,14 @@ pub async fn uploaded(req: HttpRequest) -> Result {
.map(urlencoding::decode)
.transpose()
.map_err(|_| error::ErrorBadRequest("name is invalid utf-8"))?;
- let upload_html = if name.is_some() {
+ let mut upload_html = if name.is_some() {
UPLOAD_SHORT_HTML
.replace("{link}", &get_file_url(&req, id, name.as_deref()))
.replace("{shortlink}", &get_file_url(&req, id, None))
} else {
UPLOAD_HTML.replace("{link}", &get_file_url(&req, id, name.as_deref()))
};
+ upload_html = template::insert_abuse_template(upload_html, None, &config);
Ok(HttpResponse::Ok()
.content_type("text/html")
.body(upload_html))
diff --git a/static/index.css b/static/index.css
index d8155c0..0c3a1fd 100644
--- a/static/index.css
+++ b/static/index.css
@@ -107,7 +107,7 @@ h1 + textarea {
display: none;
}
-input[type='checkbox'] {
+input[type="checkbox"] {
margin-top: 0.5em;
margin-bottom: 1.5em;
}
@@ -167,16 +167,16 @@ footer {
padding: 0.5em;
}
-.repo {
+footer > * {
padding: 0.5em;
color: var(--fg-light);
text-decoration: none;
}
-.repo:visited {
+footer > *:visited {
color: var(--fg-light);
}
-.repo:hover {
+footer > *:hover {
color: var(--fg);
}
diff --git a/template/index.html b/template/index.html
index 6f23305..7641fc9 100644
--- a/template/index.html
+++ b/template/index.html
@@ -59,8 +59,8 @@ authentifizieren