diff --git a/Cargo.lock b/Cargo.lock index 634eec6..a93d755 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1399,6 +1399,7 @@ dependencies = [ "ring", "serde", "serde_regex", + "text-template", "url", ] @@ -1563,6 +1564,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "text-template" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bcc3e9514cba67c087126b18600010c7c29b0cb51a6f6bc75e5058c2369bba" + [[package]] name = "time" version = "0.3.17" diff --git a/Cargo.toml b/Cargo.toml index 565b496..95a7180 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ humantime-serde = "1.1.1" glob = "0.3.1" ring = "0.16.20" hotwatch = "0.4.5" +text-template = "0.1.0" [dependencies.config] version = "0.13.3" diff --git a/README.md b/README.md index 0beecd2..04b73c1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -**Rustypaste** is a minimal file upload/pastebin service. +**Rustypaste-pretty** is a minimal file upload/pastebin service with client side highlighting provided by highlight.js. + +Just add `?pretty` to the end of a link to highlight! ```sh $ echo "some text" > awesome.txt diff --git a/config.toml b/config.toml index a21a040..a169a49 100644 --- a/config.toml +++ b/config.toml @@ -2,12 +2,13 @@ refresh_rate="1s" [server] -address="127.0.0.1:8000" +address="127.0.0.1:8020" #workers=4 max_content_length="10MB" upload_path="./upload" timeout="30s" expose_version=false +style="monokai" landing_page="""Submit files via HTTP POST here: curl -F 'file=@example.txt' " This will return the finished URL. @@ -42,5 +43,10 @@ mime_blacklist = [ "application/java-archive", "application/java-vm" ] + duplicate_files = true delete_expired_files = { enabled = true, interval = "1h" } + +[paste.highlight_override] +# For example, to force markdown rather than using highlight.js's autodetection +#"text/markdown" = "markdown" diff --git a/src/config.rs b/src/config.rs index ca0aec0..3bc5b8e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,6 +2,7 @@ use crate::mime::MimeMatcher; use crate::random::RandomURLConfig; use byte_unit::Byte; use config::{self, ConfigError}; +use std::collections::HashMap; use std::path::{Path, PathBuf}; use std::time::Duration; @@ -45,6 +46,8 @@ pub struct ServerConfig { pub landing_page: Option, /// Expose version. pub expose_version: Option, + /// Highlight.js style + pub style: Option, } /// Paste configuration. @@ -64,6 +67,9 @@ pub struct PasteConfig { pub duplicate_files: Option, /// Delete expired files. pub delete_expired_files: Option, + /// Highlight override. + #[serde(default)] + pub highlight_override: HashMap, } /// Cleanup configuration. @@ -80,6 +86,7 @@ impl Config { /// Parses the config file and returns the values. pub fn parse(path: &Path) -> Result { config::Config::builder() + .set_default("style", "default").unwrap() .add_source(config::File::from(path)) .add_source(config::Environment::default().separator("__")) .build()? diff --git a/src/pretty.html b/src/pretty.html new file mode 100644 index 0000000..1fa8779 --- /dev/null +++ b/src/pretty.html @@ -0,0 +1,23 @@ + + + + ${file} + + + + + +

+		
+ + diff --git a/src/server.rs b/src/server.rs index 7993562..3f99765 100644 --- a/src/server.rs +++ b/src/server.rs @@ -6,6 +6,7 @@ use crate::mime as mime_util; use crate::paste::{Paste, PasteType}; use crate::util; use crate::AUTH_TOKEN_ENV; +use text_template::*; use actix_files::NamedFile; use actix_multipart::Multipart; use actix_web::{error, get, post, web, Error, HttpRequest, HttpResponse}; @@ -16,7 +17,9 @@ use serde::Deserialize; use std::convert::TryFrom; use std::env; use std::fs; +use std::str; use std::sync::RwLock; +use std::collections::HashMap; /// Shows the landing page. #[get("/")] @@ -51,6 +54,7 @@ async fn serve( let config = config .read() .map_err(|_| error::ErrorInternalServerError("cannot acquire config"))?; + let path = config.server.upload_path.join(&*file); let mut path = util::glob_match_file(path)?; let mut paste_type = PasteType::File; @@ -78,6 +82,23 @@ async fn serve( mime_util::get_mime_type(&config.paste.mime_override, file.to_string()) .map_err(error::ErrorInternalServerError)? }; + + if request.query_string() == "pretty" { + let mut values = HashMap::new(); + let tmpl_bytes = str::from_utf8(include_bytes!("pretty.html")).unwrap(); + let tmpl = Template::from(tmpl_bytes); + values.insert("file", file.as_str()); + values.insert("style", match &config.server.style { + Some(style) => style.as_str(), + None => "default", + }); + let mime_str = mime_type.to_string(); + let overrides = &config.paste.highlight_override; + values.insert("type", if overrides.contains_key(&mime_str) { overrides[&mime_str].as_str() } else { "" }); + let rendered = tmpl.fill_in(&values); + return Ok(HttpResponse::Ok().body(rendered.to_string())) + } + let response = NamedFile::open(&path)? .disable_content_disposition() .set_content_type(mime_type)