sync: mailcore 0.2.1-beta
This commit is contained in:
133
mailcore/tests/pgp_key_extraction_test.rs
Normal file
133
mailcore/tests/pgp_key_extraction_test.rs
Normal file
@@ -0,0 +1,133 @@
|
||||
/// Tests for PGP sender public key extraction in parse_mime_message:
|
||||
/// - Autocrypt header parsing
|
||||
/// - application/pgp-keys attachment fallback
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_autocrypt_header_extracts_sender_key() {
|
||||
// Minimal PGP public key bytes (32 bytes of zeros, just enough to test
|
||||
// the base64/armor wrapping — not a valid OpenPGP cert but structurally
|
||||
// correct for the extraction path).
|
||||
let raw_key_bytes = vec![0u8; 32];
|
||||
let b64_key = {
|
||||
use std::fmt::Write as _;
|
||||
let mut s = String::new();
|
||||
for byte in &raw_key_bytes {
|
||||
write!(s, "{:02x}", byte).unwrap();
|
||||
}
|
||||
// Use standard base64 encoding
|
||||
base64_encode(&raw_key_bytes)
|
||||
};
|
||||
|
||||
let raw_email = format!(
|
||||
"From: sender@example.com\r\n\
|
||||
To: recipient@example.com\r\n\
|
||||
Subject: Test Autocrypt\r\n\
|
||||
Autocrypt: addr=sender@example.com; prefer-encrypt=mutual; keydata={b64_key}\r\n\
|
||||
MIME-Version: 1.0\r\n\
|
||||
Content-Type: text/plain\r\n\
|
||||
\r\n\
|
||||
Hello world\r\n"
|
||||
);
|
||||
|
||||
let body = mailcore::api::parse_mime_message(raw_email.as_bytes())
|
||||
.await
|
||||
.expect("parse should succeed");
|
||||
|
||||
let key = body.sender_public_key.expect("sender_public_key should be set");
|
||||
assert!(
|
||||
key.contains("-----BEGIN PGP PUBLIC KEY BLOCK-----"),
|
||||
"extracted key should be armored: {}",
|
||||
key
|
||||
);
|
||||
assert!(
|
||||
key.contains("-----END PGP PUBLIC KEY BLOCK-----"),
|
||||
"extracted key should have armor footer: {}",
|
||||
key
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_pgp_keys_attachment_extracts_sender_key() {
|
||||
let fake_armored_key = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\
|
||||
\n\
|
||||
mDMEYmFrZWtleWZha2VrZXlmYWtla2V5ZmFrZQ==\n\
|
||||
-----END PGP PUBLIC KEY BLOCK-----\n";
|
||||
|
||||
let boundary = "testboundary123";
|
||||
let raw_email = format!(
|
||||
"From: sender@example.com\r\n\
|
||||
To: recipient@example.com\r\n\
|
||||
Subject: Test PGP Keys Attachment\r\n\
|
||||
MIME-Version: 1.0\r\n\
|
||||
Content-Type: multipart/mixed; boundary=\"{boundary}\"\r\n\
|
||||
\r\n\
|
||||
--{boundary}\r\n\
|
||||
Content-Type: text/plain\r\n\
|
||||
\r\n\
|
||||
Hello world\r\n\
|
||||
\r\n\
|
||||
--{boundary}\r\n\
|
||||
Content-Type: application/pgp-keys; name=\"sender.asc\"\r\n\
|
||||
Content-Disposition: attachment; filename=\"sender.asc\"\r\n\
|
||||
\r\n\
|
||||
{fake_armored_key}\r\n\
|
||||
--{boundary}--\r\n"
|
||||
);
|
||||
|
||||
let body = mailcore::api::parse_mime_message(raw_email.as_bytes())
|
||||
.await
|
||||
.expect("parse should succeed");
|
||||
|
||||
let key = body.sender_public_key.expect("sender_public_key should be set from pgp-keys attachment");
|
||||
assert!(
|
||||
key.contains("BEGIN PGP PUBLIC KEY BLOCK"),
|
||||
"extracted key should contain PGP armor header: {}",
|
||||
key
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_no_key_in_plain_email() {
|
||||
let raw_email = "From: sender@example.com\r\n\
|
||||
To: recipient@example.com\r\n\
|
||||
Subject: Plain email\r\n\
|
||||
MIME-Version: 1.0\r\n\
|
||||
Content-Type: text/plain\r\n\
|
||||
\r\n\
|
||||
No PGP here.\r\n";
|
||||
|
||||
let body = mailcore::api::parse_mime_message(raw_email.as_bytes())
|
||||
.await
|
||||
.expect("parse should succeed");
|
||||
|
||||
assert!(
|
||||
body.sender_public_key.is_none(),
|
||||
"sender_public_key should be None for plain emails"
|
||||
);
|
||||
}
|
||||
|
||||
/// Simple base64 encoder (standard alphabet, no line breaks) for test use.
|
||||
fn base64_encode(input: &[u8]) -> String {
|
||||
const ALPHABET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
let mut out = String::new();
|
||||
let mut i = 0;
|
||||
while i < input.len() {
|
||||
let b0 = input[i] as usize;
|
||||
let b1 = if i + 1 < input.len() { input[i + 1] as usize } else { 0 };
|
||||
let b2 = if i + 2 < input.len() { input[i + 2] as usize } else { 0 };
|
||||
out.push(ALPHABET[(b0 >> 2)] as char);
|
||||
out.push(ALPHABET[((b0 & 3) << 4) | (b1 >> 4)] as char);
|
||||
if i + 1 < input.len() {
|
||||
out.push(ALPHABET[((b1 & 0xf) << 2) | (b2 >> 6)] as char);
|
||||
} else {
|
||||
out.push('=');
|
||||
}
|
||||
if i + 2 < input.len() {
|
||||
out.push(ALPHABET[b2 & 0x3f] as char);
|
||||
} else {
|
||||
out.push('=');
|
||||
}
|
||||
i += 3;
|
||||
}
|
||||
out
|
||||
}
|
||||
Reference in New Issue
Block a user