diff --git a/Cargo.lock b/Cargo.lock index 9e4728f..dc2d917 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -424,7 +424,7 @@ dependencies = [ [[package]] name = "datatrash" -version = "2.1.1" +version = "2.2.0" dependencies = [ "actix-files", "actix-governor", diff --git a/Cargo.toml b/Cargo.toml index 7c13d80..45aed52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "datatrash" -version = "2.1.1" +version = "2.2.0" authors = ["neri"] edition = "2021" diff --git a/src/download.rs b/src/download.rs index e3bc828..3b5ce69 100644 --- a/src/download.rs +++ b/src/download.rs @@ -15,13 +15,9 @@ use sqlx::postgres::PgPool; use std::path::Path; use time::OffsetDateTime; use tokio::fs; -use url::Url; 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"); - const TEXT_VIEW_SIZE_LIMIT: u64 = 512 * 1024; // 512KiB enum ViewType { @@ -130,20 +126,10 @@ async fn build_html_response( 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 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); + let html_view = template::build_html_view_template(&content, req, config); Ok(HttpResponse::Ok() .content_type(TEXT_HTML.to_string()) - .body(html)) + .body(html_view)) } fn build_file_response( diff --git a/src/template.rs b/src/template.rs index 2708418..b0b4791 100644 --- a/src/template.rs +++ b/src/template.rs @@ -1,8 +1,9 @@ -use std::{cmp, io::ErrorKind}; +use std::{cmp, io::ErrorKind, str::FromStr}; use actix_web::HttpRequest; use time::Duration; use tokio::fs; +use url::Url; use crate::config::Config; @@ -10,8 +11,54 @@ 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"); +const UPLOAD_HTML: &str = include_str!("../template/upload.html"); +const UPLOAD_SHORT_HTML: &str = include_str!("../template/upload-short.html"); + +const TEXT_VIEW_HTML: &str = include_str!("../template/text-view.html"); +const URL_VIEW_HTML: &str = include_str!("../template/url-view.html"); + +pub fn build_uploaded_html( + req: &HttpRequest, + id: &str, + name: Option<&str>, + config: &Config, +) -> String { + let upload_html = if name.is_some() { + UPLOAD_SHORT_HTML + .replace("{link}", &get_file_url(req, id, name)) + .replace("{shortlink}", &get_file_url(req, id, None)) + } else { + UPLOAD_HTML.replace("{link}", &get_file_url(req, id, name)) + }; + insert_abuse_template(upload_html, None, config) +} + +pub fn get_file_url(req: &HttpRequest, id: &str, name: Option<&str>) -> String { + let host = get_host_url(req); + if let Some(name) = name { + let encoded_name = urlencoding::encode(name); + format!("{host}/{id}/{encoded_name}") + } else { + format!("{host}/{id}") + } +} + +pub fn build_html_view_template(content: &str, req: &HttpRequest, config: &Config) -> String { + 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) + }; + insert_abuse_template(html, Some(req), config) +} + pub async fn write_prefillable_templates(config: &Config) { let index_path = config.static_dir.join("index.html"); fs::write(index_path, build_index_html(config)) diff --git a/src/upload.rs b/src/upload.rs index a25f250..dcf086a 100644 --- a/src/upload.rs +++ b/src/upload.rs @@ -13,9 +13,6 @@ use std::path::PathBuf; use tokio::fs::{self, OpenOptions}; use tokio::sync::mpsc::Sender; -const UPLOAD_HTML: &str = include_str!("../template/upload.html"); -const UPLOAD_SHORT_HTML: &str = include_str!("../template/upload-short.html"); - const ID_CHARS: &[char] = &[ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9', @@ -63,7 +60,7 @@ pub async fn upload( expiry_watch_sender.send(()).await.unwrap(); let redirect = get_redirect_url(&file_id, upload_config.original_name.as_deref()); - let url = get_file_url(&req, &file_id, upload_config.original_name.as_deref()); + let url = template::get_file_url(&req, &file_id, upload_config.original_name.as_deref()); Ok(HttpResponse::SeeOther() .insert_header((LOCATION, redirect)) .body(format!("{url}\n"))) @@ -125,16 +122,6 @@ fn gen_file_id() -> String { .collect() } -fn get_file_url(req: &HttpRequest, id: &str, name: Option<&str>) -> String { - let host = template::get_host_url(req); - if let Some(name) = name { - let encoded_name = urlencoding::encode(name); - format!("{host}/{id}/{encoded_name}") - } else { - format!("{host}/{id}") - } -} - fn get_redirect_url(id: &str, name: Option<&str>) -> String { if let Some(name) = name { let encoded_name = urlencoding::encode(name); @@ -152,15 +139,8 @@ pub async fn uploaded(req: HttpRequest, config: web::Data) -> Result