crabmail

Static HTML email archive viewer in Rust
git clone git://git.alexwennerberg.com/crabmail
Log | Files | Refs | README | LICENSE

commit 1bccade8a1eea68a3bd2689abfe4a1ddcbdcdf27
parent 8acf05bee5d2a1286e12f7eb6e0489d099fef773
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Tue, 14 Dec 2021 14:40:32 -0800

replace date with hash

Diffstat:
MCargo.lock | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MCargo.toml | 2++
Msrc/main.rs | 22+++++++++++++++++++++-
3 files changed, 92 insertions(+), 1 deletion(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -115,6 +115,15 @@ dependencies = [ ] [[package]] +name = "block-buffer" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95" +dependencies = [ + "generic-array", +] + +[[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -143,14 +152,36 @@ dependencies = [ "ammonia", "anyhow", "askama", + "hex", "mailparse", "mbox-reader", "pico-args", "quick-xml", + "sha3", "url", ] [[package]] +name = "crypto-common" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b" +dependencies = [ + "block-buffer", + "crypto-common", + "generic-array", +] + +[[package]] name = "encoding_rs" version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -186,6 +217,16 @@ dependencies = [ ] [[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] name = "getrandom" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -197,6 +238,12 @@ dependencies = [ ] [[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] name = "html5ever" version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -228,6 +275,12 @@ dependencies = [ ] [[package]] +name = "keccak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" + +[[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -548,6 +601,16 @@ dependencies = [ ] [[package]] +name = "sha3" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f935e31cf406e8c0e96c2815a5516181b7004ae8c5f296293221e9b1e356bd" +dependencies = [ + "digest", + "keccak", +] + +[[package]] name = "siphasher" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -648,6 +711,12 @@ dependencies = [ ] [[package]] +name = "typenum" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" + +[[package]] name = "unicode-bidi" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml @@ -13,6 +13,8 @@ html = ["ammonia"] [dependencies] mailparse = "0.13" url = "2" +hex = "0.4" +sha3 = "0.10" mbox-reader = "0.2.0" #unamaintained, should remove dep pico-args = "0.4.1" askama = "0.10" diff --git a/src/main.rs b/src/main.rs @@ -1,7 +1,12 @@ use anyhow::{anyhow, Context, Result}; use askama::Template; +use hex; use mailparse::*; use mbox_reader::MboxFile; +use sha3::{ + digest::{ExtendableOutput, Update, XofReader}, + Shake128, +}; use std::collections::HashMap; use std::fs::OpenOptions; use std::io::prelude::*; @@ -44,6 +49,17 @@ impl Email { url.query_pairs_mut().append_pair("subject", &self.subject); url.into() } + + // Build hash string from message ID + // This allows for a stable, url-friendly filename + pub fn hash(&self) -> String { + let mut hasher = Shake128::default(); + hasher.update(&self.id.as_bytes()); + let mut reader = hasher.finalize_xof(); + let mut res1 = [0u8; 6]; + XofReader::read(&mut reader, &mut res1); + return hex::encode(&res1); + } } #[cfg(feature = "html")] @@ -199,7 +215,7 @@ fn main() -> Result<()> { .create(true) .write(true) .truncate(true) - .open(thread_dir.join(format!("{}.html", root.date)))?; + .open(thread_dir.join(format!("{}.html", root.hash())))?; file.write(Thread { root, messages }.render()?.as_bytes()) .ok(); } @@ -221,6 +237,10 @@ fn main() -> Result<()> { Ok(()) } +// TODO +// delete all files +fn remove_missing() {} + fn parse_path(s: &std::ffi::OsStr) -> Result<std::path::PathBuf, &'static str> { Ok(s.into()) }