Add matching rust implementation for Go HashMessage.

This commit is contained in:
Bill Thiede 2023-02-22 20:47:14 -08:00
parent af87a3cade
commit 7bbdaec84b
5 changed files with 180 additions and 33 deletions

117
Cargo.lock generated
View File

@ -13,60 +13,112 @@ dependencies = [
[[package]]
name = "base64"
version = "0.10.1"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "block-buffer"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
dependencies = [
"byteorder",
"generic-array",
]
[[package]]
name = "byteorder"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
[[package]]
name = "cfg-if"
version = "0.1.10"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "charset"
version = "0.1.2"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f426e64df1c3de26cbf44593c6ffff5dbfd43bbf9de0d075058558126b3fc73"
checksum = "18e9079d1a12a2cc2bffb5db039c43661836ead4082120d5844f02555aca2d46"
dependencies = [
"base64",
"encoding_rs",
]
[[package]]
name = "cpufeatures"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "data-encoding"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
[[package]]
name = "digest"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "email"
version = "0.1.0"
dependencies = [
"mailparse",
"regex",
"sha1",
]
[[package]]
name = "encoding_rs"
version = "0.8.20"
version = "0.8.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87240518927716f79692c2ed85bfe6e98196d18c6401ec75355760233a7e12e9"
checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
dependencies = [
"cfg-if",
]
[[package]]
name = "mailparse"
version = "0.9.2"
name = "generic-array"
version = "0.14.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51a60bad00d8aa905d31cf239f207ad4ef16c963ea53cf522d5fd7dc7f3ecfe2"
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "libc"
version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "mailparse"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b56570f5f8c0047260d1c8b5b331f62eb9c660b9dd4071a8c46f8c7d3f280aa"
dependencies = [
"base64",
"charset",
"data-encoding",
"quoted_printable",
]
@ -78,9 +130,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "quoted_printable"
version = "0.4.1"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86cedf331228892e747bb85beb130b6bb23fc628c40dde9ea01eb6becea3c798"
checksum = "a24039f627d8285853cc90dcddf8c1ebfaa91f834566948872b225b9a28ed1b6"
[[package]]
name = "regex"
@ -98,3 +150,26 @@ name = "regex-syntax"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "sha1"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "typenum"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"

View File

@ -7,5 +7,6 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
mailparse = "0.9.2"
mailparse = "0.14.0"
regex = "1.7.0"
sha1 = "0.10.5"

24
hash_test.go Normal file
View File

@ -0,0 +1,24 @@
package email
import (
"net/mail"
"testing"
)
func TestHashReader(t *testing.T) {
got, err := HashMessage(&mail.Message{
Header: mail.Header{
"Subject": []string{"Test"},
"From": []string{"me@myself.com"},
"To": []string{"you@yourself.com"},
},
Body: nil,
})
if err != nil {
t.Errorf("Failed to parse: %v", err)
}
want := "1b25d59ed0ade6a762145c58643717477b054fd1"
if got != want {
t.Errorf("HashReader(msg) = %s; want %s", got, want)
}
}

View File

@ -1,12 +1,6 @@
use std::env;
use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::process::exit;
use std::slice::Iter;
use std::{env, error::Error, fs::File, io::prelude::*, process::exit, slice::Iter};
use mailparse::dateparse;
use mailparse::MailHeaderMap;
use mailparse::{dateparse, MailHeaderMap};
fn newline(b: &u8) -> bool {
*b == b'\n'
@ -57,15 +51,15 @@ fn parse_mbox(mbox_bytes: &Vec<u8>) -> Result<(), Box<dyn Error>> {
let mail = mailparse::parse_mail(mail_bytes).unwrap();
println!(
"{:?} {:?} from {:?}",
match mail.headers.get_first_value("Date")? {
match mail.headers.get_first_value("Date") {
Some(date) => date,
None => "NO DATE".to_string(),
},
match mail.headers.get_first_value("Subject")? {
match mail.headers.get_first_value("Subject") {
Some(subject) => subject,
None => "NO SUBJECT".to_string(),
},
match mail.headers.get_first_value("From")? {
match mail.headers.get_first_value("From") {
Some(from) => from,
None => "NO FROM".to_string(),
},

53
src/lib.rs Normal file
View File

@ -0,0 +1,53 @@
use mailparse::{parse_headers, MailHeader, MailHeaderMap};
use sha1::{Digest, Sha1};
// Keep these sorted to match Go implementation.
const IMPORTANT_HEADERS: &[&str] = &[
"cc",
"date",
"from",
"message-id",
"received",
"subject",
"to",
];
pub fn hash_headers(hdrs: &[MailHeader]) -> String {
// create a Sha1 object
let mut hasher = Sha1::new();
for h in IMPORTANT_HEADERS {
if let Some(v) = hdrs.get_first_value(h) {
eprintln!("V [{}]", v);
hasher.update(v);
}
}
format!("{:x}", hasher.finalize())
}
#[cfg(test)]
mod tests {
use mailparse::{parse_headers, MailHeader, MailHeaderMap};
#[test]
fn hash_headers() {
let (hdrs, _) = parse_headers(
concat!(
"Subject: Test\n",
"From: me@myself.com\n",
"To: you@yourself.com"
)
.as_bytes(),
)
.unwrap();
assert_eq!(hdrs[1].get_key(), "From");
assert_eq!(
hdrs.get_first_value("To"),
Some("you@yourself.com".to_string())
);
assert_eq!(
super::hash_headers(&hdrs),
"1b25d59ed0ade6a762145c58643717477b054fd1"
);
}
}