diff --git a/.gitignore b/.gitignore index f41a9aa..cbdb1c0 100644 --- a/.gitignore +++ b/.gitignore @@ -139,3 +139,4 @@ cython_debug/ # Added by cargo /target +/cache \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 5471d2e..2eaeaca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,7 +66,7 @@ dependencies = [ "http", "httparse", "httpdate", - "itoa", + "itoa 1.0.4", "language-tags", "local-channel", "mime", @@ -176,7 +176,7 @@ dependencies = [ "futures-core", "futures-util", "http", - "itoa", + "itoa 1.0.4", "language-tags", "log", "mime", @@ -686,7 +686,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", - "itoa", + "itoa 1.0.4", ] [[package]] @@ -739,7 +739,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa", + "itoa 1.0.4", "pin-project-lite", "socket2", "tokio", @@ -820,6 +820,12 @@ version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + [[package]] name = "itoa" version = "1.0.4" @@ -908,6 +914,28 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "maud" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19aff2cd19eb4b93df29efa602652513b0f731f1d3474f6e377f763fddf61e58" +dependencies = [ + "itoa 0.4.8", + "maud_macros", +] + +[[package]] +name = "maud_macros" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c114f6f24b08fdd4a25d2fb87a8b140df56b577723247b382e8b04c583f2eb" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "me-site" version = "0.1.0" @@ -918,6 +946,7 @@ dependencies = [ "env_logger", "gnupg", "log", + "maud", "reqwest", "serde", "serde_json", @@ -1124,6 +1153,30 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.47" @@ -1336,7 +1389,7 @@ version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" dependencies = [ - "itoa", + "itoa 1.0.4", "ryu", "serde", ] @@ -1348,7 +1401,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa", + "itoa 1.0.4", "ryu", "serde", ] @@ -1449,7 +1502,7 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" dependencies = [ - "itoa", + "itoa 1.0.4", "serde", "time-core", "time-macros", @@ -1738,10 +1791,11 @@ checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "web-base" version = "0.1.0" -source = "git+https://git.hydrar.de/jmarya/web-base#d7ca4a0dd03f6f803b3059a357b8b53bf2c847a6" +source = "git+https://git.hydrar.de/jmarya/web-base#dd70137cb7557931cddbe700a0f49ecca35c2988" dependencies = [ "actix-files", "actix-web", + "maud", "reqwest", "uuid", ] diff --git a/Cargo.toml b/Cargo.toml index 93dcce5..e280b77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,4 +15,5 @@ gnupg = { git = "https://git.hydrar.de/jmarya/gnupg-rs" } web-base = { git = "https://git.hydrar.de/jmarya/web-base" } serde = {version = "1.0.147", features = ["derive"] } serde_json = "1.0.87" -reqwest = "0.11" \ No newline at end of file +reqwest = "0.11" +maud = "0.24.0" diff --git a/Dockerfile b/Dockerfile index d67682d..a969f84 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,8 +10,8 @@ FROM debian RUN apt-get update RUN apt-get install -y gnupg ca-certificates -COPY --from=builder /app/target/release/me-site /app/me-site +COPY --from=builder /app/target/release/me-site /me-site WORKDIR /app -CMD ["/app/me-site"] +CMD ["/me-site"] diff --git a/src/config.rs b/src/config.rs index 1f1d530..3786ec8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -18,8 +18,8 @@ fn read_json_file(f: &str) -> Option { impl Config { pub fn new() -> Config { - let v = read_json_file("/config/config.json").expect("could not read config file"); - let c = read_json_file("/config/colors.json"); + let v = read_json_file("./config/config.json").expect("could not read config file"); + let c = read_json_file("./config/colors.json"); Config { root: v, color: c } } diff --git a/src/msg.rs b/src/msg.rs index 272f850..e49adf0 100644 --- a/src/msg.rs +++ b/src/msg.rs @@ -3,16 +3,16 @@ use std::io::Write; pub fn encrypt(msg: String) -> String { let pgp = gnupg::GnuPG::new().unwrap(); let pub_key = pgp - .import_key(&std::fs::read_to_string("/config/pub.key").unwrap()) + .import_key(&std::fs::read_to_string("./config/pub.key").unwrap()) .unwrap(); let c = pgp.encrypt(&pub_key, &msg).unwrap(); return c; } pub fn save_msg(msg: String, name: &str) { - std::fs::create_dir_all("/data/messages").expect("couldn't create msg dir"); + std::fs::create_dir_all("./data/messages").expect("couldn't create msg dir"); let time = chrono::offset::Utc::now(); let time = time.format("%Y-%m-%d.%H-%M").to_string(); - let mut f = std::fs::File::create(format!("/data/messages/{name}-{time}.asc")).unwrap(); + let mut f = std::fs::File::create(format!("./data/messages/{name}-{time}.asc")).unwrap(); f.write_all(encrypt(msg).as_bytes()).unwrap(); } diff --git a/src/pages/assets.rs b/src/pages/assets.rs index 8e8a0ad..56d857f 100644 --- a/src/pages/assets.rs +++ b/src/pages/assets.rs @@ -5,10 +5,10 @@ use actix_web::*; #[get("/assets/wall")] pub(crate) async fn wallpaper() -> Result { - Ok(NamedFile::open("/config/wall.avif")?) + Ok(NamedFile::open("./config/wall.avif")?) } #[get("/assets/me")] pub(crate) async fn me_img() -> Result { - Ok(NamedFile::open("/config/me.avif")?) + Ok(NamedFile::open("./config/me.avif")?) } diff --git a/src/pages/html_fn.rs b/src/pages/html_fn.rs index bc8c37e..f6827fa 100644 --- a/src/pages/html_fn.rs +++ b/src/pages/html_fn.rs @@ -1,6 +1,7 @@ use crate::config::Config; use actix_web::web::Data; use actix_web::*; +use maud::{html, PreEscaped}; pub(crate) async fn build_site( content: String, @@ -9,11 +10,11 @@ pub(crate) async fn build_site( shadow: bool, config: &Data, ) -> HttpResponse { - const BOOTSTRAP: &str = r#" - - - - "#; + let BOOTSTRAP = html! { + link href="/bootstrap.min.css" rel="stylesheet"; + link href="/bootstrap-icons.css" rel="stylesheet"; + link href="/bootstrap.bundle.min.js" rel="stylesheet"; + }; let mut c_class = "bg-dark text-white justify-content-center text-center".to_string(); let mut c_style = "".to_string(); @@ -25,31 +26,28 @@ pub(crate) async fn build_site( g_style = format!("a {{text-decoration: none; font-weight: bold; color: {fg}}}"); } } - if std::path::Path::new("/config/wall.avif").exists() { + if std::path::Path::new("./config/wall.avif").exists() { c_style.push_str("background-image: url('assets/wall');background-size:cover;"); } if shadow { c_style.push_str("text-shadow: 1px 1px 3px black;"); } - let r = format!( - " - - - - {title} - -{BOOTSTRAP} - - - -{content} - - - " - ); + let r = html! { + (maud::DOCTYPE) + html { + head { + title { + (title) + }; + (BOOTSTRAP) + }; + body style=(c_style) class=(c_class) { + style { (g_style) }; + (PreEscaped(content)) + } + }; + }; - return HttpResponse::Ok().message_body(r).unwrap(); + return HttpResponse::Ok().message_body(r.into_string()).unwrap(); } diff --git a/src/pages/index.rs b/src/pages/index.rs index cd5879b..35a8241 100644 --- a/src/pages/index.rs +++ b/src/pages/index.rs @@ -2,6 +2,7 @@ use crate::{config, pages}; use actix_web::http::header; use actix_web::web::Form; use actix_web::*; +use maud::{html, PreEscaped}; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] @@ -20,45 +21,45 @@ pub async fn message_post(r: HttpRequest, f: Form) -> impl Responde config.clone(), ) .await; - return HttpResponse::Found() - .append_header(("Location", "/message")) - .finish(); + return web_base::func::redirect("/message"); } #[get("/message")] pub async fn message_page(r: HttpRequest) -> impl Responder { let config: &web::Data = r.app_data().unwrap(); let host = web_base::func::get_host(&r); - let resp = format!( - r#" -

Message

-
-
- - - -
-
- "# - ); - return pages::html_fn::build_site(resp, "Message", false, true, config).await; + + let resp = html! { + div class="container" style="margin-top: 25px" { + h1 { "Message" }; + br; + + form action=(format!("http://{host}")) method="post" autocomplete="off" { + input value="" type="text" required name="msg_name" placeholder="Name" class="form-control bg-dark text-white" style="margin-bottom: 15px"; + textarea placeholder="Message" required name="message" cols="10" rows="10" class="form-control bg-dark text-white" style="margin-bottom: 15px;"; + input value="Send Message" type="submit" required name="submit" class="btn btn-danger text-white text-decoration-none"; + } + } + }; + + return pages::html_fn::build_site(resp.into_string(), "Message", false, true, config).await; } #[get("/mirrors.txt")] pub async fn mirrors(r: HttpRequest) -> impl Responder { let config: &web::Data = r.app_data().unwrap(); - if let Ok(mirror_file) = std::fs::File::open("/config/mirrors.txt") { + if let Ok(mirror_file) = std::fs::File::open("./config/mirrors.txt") { let content = std::io::read_to_string(mirror_file).unwrap(); if web_base::func::is_browser(&r) { - let resp = format!( - r#" -
-
 {content} 
-
- "# - ); - return pages::html_fn::build_site(resp, "Mirrors", false, true, config).await; + let resp = html! { + div style="margin: 25px;" { + pre { + (content) + }; + } + }; + return pages::html_fn::build_site(resp.into_string(), "Mirrors", false, true, config) + .await; } let res: HttpResponse = HttpResponse::Ok().message_body(content).unwrap(); return res; @@ -74,28 +75,30 @@ pub async fn public_key(r: HttpRequest) -> impl Responder { if web_base::func::is_browser(&r) { let config: &web::Data = r.app_data().unwrap(); let host = format!("http://{}", web_base::func::get_host(&r)); - let key = std::io::read_to_string(std::fs::File::open("/config/pub.key").unwrap()).unwrap(); + let key = + std::io::read_to_string(std::fs::File::open("./config/pub.key").unwrap()).unwrap(); let pgp = gnupg::GnuPG::new().unwrap(); let key_name = pgp.import_key(&key).unwrap().name; - let key = key.replace("\n", "
"); - let resp = format!( - r#" -
-
- To Import: - -curl -sL "{host}/public_key"|gpg --import -
-

{key_name}

-
-

{key}

- "# - ); - return pages::html_fn::build_site(resp, "Public Key", true, false, config).await; + + let resp = html! { + div class="container" style="margin-top: 25px" { + div class="alert alert-info" { + b { "To Import: " }; + span style="display: block;font-family: monospace,monospace;margin-top: 10px; font-size: 20px;overflow-wrap: break-word;" { (format!("curl -sL \"{host}/public_key\"|gpg --import")) }; + }; + h4 class="container card" style="padding-top: 10px; padding-bottom: 10px; background: black; margin-bottom: 15px;" { (key_name) }; + }; + div class="container card bg-primary" { + p { (PreEscaped(key)) } + } + }; + + return pages::html_fn::build_site(resp.into_string(), "Public Key", true, false, config) + .await; } - if let Ok(key_f) = std::fs::File::open("/config/pub.key") { + if let Ok(key_f) = std::fs::File::open("./config/pub.key") { if let Ok(key_data) = std::io::read_to_string(key_f) { let res: HttpResponse = HttpResponse::Ok() .insert_header(header::ContentType::plaintext()) @@ -113,42 +116,43 @@ curl -sL "{host}/public_key"|gpg --import fn build_information_block(conf: &web::Data) -> String { let name = conf.name().unwrap(); - format!( - r#" -
-Me -

-

{name}

-
-
- "# - ) + return html! { + div class="container border-dark" style="margin-top: 20px" { + img src="/assets/me" height="200" width="200" alt="Me" class="rounded"; + br;br; + h1 { (name) }; + hr; + } + } + .into_string(); } fn build_contact_block(conf: &web::Data) -> String { if let Some(email) = conf.email() { - let pgp_key_message = match std::path::Path::new("/config/pub.key").exists() { - true => { - r#" - My PGP Key -
- Write a message -

- "# + let pgp_key_message = match std::path::Path::new("./config/pub.key").exists() { + true => html! { + a href="/public_key" { "My PGP Key" }; + br; + a href="/message" { "Write a message" }; + br;br; } - false => "", + .into_string(), + false => "".to_string(), }; - return format!( - r#" -
-

Contact

-
-{pgp_key_message} - {email} -
-
- "# - ); + + return html! { + div class="container border-dark" { + h1 { + span class="bi bi-person-lines-fill" style="vertical-align: middle;"; + span { "Contact" }; + }; + hr; + (PreEscaped(pgp_key_message)); + a href=(format!("mailto:{email}")) { (email) }; + hr; + } + } + .into_string(); } else { return "".to_string(); } @@ -156,15 +160,20 @@ fn build_contact_block(conf: &web::Data) -> String { fn build_donation_block(conf: &web::Data) -> String { if let Some(xmr_addr) = conf.xmr_address() { - format!( - r#" -
-

Donation

-
-

Monero: {xmr_addr}

-
- "# - ) + html! { + div class="container" style="margin-top: 20px" { + h1 { + span class="bi bi-cash-coin"; + span { "Donation" }; + }; + hr; + p { + b { "Monero: " }; + span style="color: orange;overflow-wrap: break-word;" { (xmr_addr) }; + } + } + } + .into_string() } else { return "".to_string(); }