From 4cd3cead882b932729388ee0c6e3ff36d7dd2c5f Mon Sep 17 00:00:00 2001 From: neri Date: Sat, 11 Feb 2023 00:16:51 +0100 Subject: [PATCH] feat: add abuse mail link to footer --- README.md | 3 ++- snippet/abuse.html.snippet | 6 ++++++ src/config.rs | 3 +++ src/download.rs | 28 +++++++++++++++++----------- src/template.rs | 18 ++++++++++++++++++ src/upload.rs | 5 +++-- static/index.css | 8 ++++---- template/index.html | 2 +- template/text-view.html | 2 +- template/upload-short.html | 2 +- template/upload.html | 2 +- template/url-view.html | 2 +- 12 files changed, 58 insertions(+), 23 deletions(-) create mode 100644 snippet/abuse.html.snippet 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