From e373f154dbeacc5a0e83b4ec73c3aa316239c029 Mon Sep 17 00:00:00 2001 From: ops Date: Sun, 18 Oct 2026 13:00:05 +0000 Subject: Remove "Message Me" functionality Remove the custom message me form to reduce maintenance burden May potentially add it again (improved). --- contact-service/src/main.rs | 220 -------------------------------------------- 1 file changed, 220 deletions(-) delete mode 100644 contact-service/src/main.rs (limited to 'contact-service/src/main.rs') diff --git a/contact-service/src/main.rs b/contact-service/src/main.rs deleted file mode 100644 index 1abfe04..0000000 --- a/contact-service/src/main.rs +++ /dev/null @@ -1,220 +0,0 @@ -//! Website Contact Form - -// Copyright (C) 2026 Doan Luu Duc Tai -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use axum::{ - extract::{Form, State}, - response::Html, - routing::post, - Router, -}; -use chrono::Utc; -use serde::Deserialize; -use std::io::Write; -use std::path::PathBuf; -use std::process::{Command, Stdio}; -use std::sync::Arc; - -#[derive(Clone)] -struct AppConfig { - bind_addr: String, - cert_path: PathBuf, - inbox_dir: PathBuf, - sq_bin: PathBuf, -} - -impl AppConfig { - fn from_env() -> Self { - let home = std::env::var("HOME").unwrap_or_else(|_| "/home/ops".into()); - - Self { - bind_addr: std::env::var("BIND_ADDR").unwrap_or_else(|_| "0.0.0.0:8085".into()), - cert_path: PathBuf::from( - std::env::var("CERT_PATH") - .unwrap_or_else(|_| format!("{}/stack/contact-cert.pgp", home)), - ), - inbox_dir: PathBuf::from( - std::env::var("INBOX_DIR") - .unwrap_or_else(|_| format!("{}/stack/inbox", home)), - ), - sq_bin: PathBuf::from( - std::env::var("SQ_BIN") - .unwrap_or_else(|_| format!("{}/.cargo/bin/sq", home)), - ), - } - } -} - -#[derive(Deserialize)] -struct ContactForm { - sender: Option, - message: String, -} - -#[tokio::main] -async fn main() { - let config = Arc::new(AppConfig::from_env()); - - let app = Router::new() - .route("/send-message", post(handle_message)) - .with_state(config.clone()); - - let listener = tokio::net::TcpListener::bind(&config.bind_addr) - .await - .unwrap_or_else(|_| panic!("Failed to bind to {}", config.bind_addr)); - - println!("Contact backend listening on http://{}", config.bind_addr); - println!("Using PQC Cert: {:?}", config.cert_path); - println!("Storing inbox in: {:?}", config.inbox_dir); - - axum::serve(listener, app).await.unwrap(); -} - -async fn handle_message( - State(config): State>, - Form(form): Form, -) -> Html<&'static str> { - let message = form.message.trim(); - if message.is_empty() { - return Html(ERROR_PAGE); - } - - let raw_sender = form.sender.as_deref().unwrap_or("").trim(); - let sender_display = if raw_sender.is_empty() { - "Anonymous" - } else { - raw_sender - }; - - let now = Utc::now(); - let timestamp_str = now.format("%Y-%m-%d_%H-%M-%S").to_string(); - - let sanitized_sender: String = raw_sender - .chars() - .filter(|c| c.is_ascii_alphanumeric() || *c == '-' || *c == '_') - .take(30) - .collect(); - - let filename = if sanitized_sender.is_empty() { - format!("{}.pgp", timestamp_str) - } else { - format!("{}_{}.pgp", timestamp_str, sanitized_sender) - }; - - let output_path = config.inbox_dir.join(filename); - - let payload = format!( - "=== BEGIN MESSAGE ===\nSender: {}\nTimestamp: {}\n============================\n\n{}", - sender_display, - now.to_rfc3339(), - message - ); - - let mut child = match Command::new(&config.sq_bin) - .args([ - "encrypt", - "--for-file", - config.cert_path.to_str().unwrap_or_default(), - "--without-signature", - ]) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - { - Ok(proc) => proc, - Err(e) => { - eprintln!("Failed to spawn sq binary ({:?}): {}", config.sq_bin, e); - return Html(ERROR_PAGE); - } - }; - - if let Some(mut stdin) = child.stdin.take() { - if stdin.write_all(payload.as_bytes()).is_err() { - return Html(ERROR_PAGE); - } - } - - let output = match child.wait_with_output() { - Ok(out) => out, - Err(_) => return Html(ERROR_PAGE), - }; - - if !output.status.success() { - eprintln!( - "sq encryption failed: {}", - String::from_utf8_lossy(&output.stderr) - ); - return Html(ERROR_PAGE); - } - - if std::fs::write(&output_path, &output.stdout).is_err() { - eprintln!("Failed to write to file {:?}", output_path); - return Html(ERROR_PAGE); - } - - Html(SUCCESS_PAGE) -} - -const SUCCESS_PAGE: &str = r#" - - - - - Message Sent - - - -
-
[ JS-free ]
-
-
-
-
-+------------------------------------------------------------------------------+
-| [+] Success: Message encrypted and delivered to inbox.                       |
-+------------------------------------------------------------------------------+
-
-<-- Return to Home Page
-            
- -
-
- -"#; - -const ERROR_PAGE: &str = r#" - - - - Error - - - -
-[!] Error: Unable to process or encrypt message.
-
-<-- Try Again
-    
- -"#; -- cgit v1.2.3