Compare commits

..

3 Commits

Author SHA1 Message Date
link2xt
9908be06dc feat: enable draft-pqc feature on pgp crate
This is needed to have support of v6 PQC keys
by the time users start generating profiles
using such keys.

Test key was generated with rsop/v0.10.0-16-gd98265f
(commit d98265f821e7bb181d06da1d634c5c4668d89e83)
using the command
cargo run --features draft-pqc generate-key \
          --profile draft-ietf-openpgp-pqc-14-v6-ed25519-mlkem768x25519
2026-05-09 15:39:36 +02:00
link2xt
4e8f6dc083 chore: update zerocopy from 0.7.32 to 0.7.35
Otherwise dependency resolver fails
if you enable "draft-pqc" feature on "pgp" crate.
2026-05-09 14:54:46 +02:00
link2xt
5edf9e2007 test: set email addresses explicitly for the test accounts
v6 keys will not have User IDs, so email addresses
cannot be extracted from there.
2026-05-09 14:54:46 +02:00
25 changed files with 302 additions and 404 deletions

88
Cargo.lock generated
View File

@@ -2608,6 +2608,25 @@ dependencies = [
"libm",
]
[[package]]
name = "hybrid-array"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2d35805454dc9f8662a98d6d61886ffe26bd465f5960e0e55345c70d5c0d2a9"
dependencies = [
"typenum",
]
[[package]]
name = "hybrid-array"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "891d15931895091dea5c47afa5b3c9a01ba634b311919fd4d41388fa0e3d76af"
dependencies = [
"typenum",
"zeroize",
]
[[package]]
name = "hyper"
version = "1.9.0"
@@ -3257,6 +3276,16 @@ dependencies = [
"cpufeatures 0.2.17",
]
[[package]]
name = "kem"
version = "0.3.0-pre.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b8645470337db67b01a7f966decf7d0bafedbae74147d33e641c67a91df239f"
dependencies = [
"rand_core 0.6.4",
"zeroize",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
@@ -3470,6 +3499,35 @@ dependencies = [
"windows-sys 0.61.1",
]
[[package]]
name = "ml-dsa"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac4a46643af2001eafebcc37031fc459eb72d45057aac5d7a15b00046a2ad6db"
dependencies = [
"const-oid",
"hybrid-array 0.3.1",
"num-traits",
"pkcs8",
"rand_core 0.6.4",
"sha3",
"signature",
"zeroize",
]
[[package]]
name = "ml-kem"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de49b3df74c35498c0232031bb7e85f9389f913e2796169c8ab47a53993a18f"
dependencies = [
"hybrid-array 0.2.3",
"kem",
"rand_core 0.6.4",
"sha3",
"zeroize",
]
[[package]]
name = "moka"
version = "0.12.10"
@@ -4205,6 +4263,8 @@ dependencies = [
"k256",
"log",
"md-5",
"ml-dsa",
"ml-kem",
"nom 8.0.0",
"num-bigint-dig",
"num-traits",
@@ -4223,6 +4283,7 @@ dependencies = [
"sha2",
"sha3",
"signature",
"slh-dsa",
"smallvec",
"snafu",
"twofish",
@@ -5687,6 +5748,25 @@ dependencies = [
"autocfg",
]
[[package]]
name = "slh-dsa"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd2f20f4049197e03db1104a6452f4d9e96665d79f880198dce4a7026ba5f267"
dependencies = [
"const-oid",
"digest",
"hmac",
"hybrid-array 0.3.1",
"pkcs8",
"rand_core 0.6.4",
"sha2",
"sha3",
"signature",
"typenum",
"zerocopy",
]
[[package]]
name = "smallvec"
version = "1.15.1"
@@ -7425,9 +7505,9 @@ checksum = "2164e798d9e3d84ee2c91139ace54638059a3b23e361f5c11781c2c6459bde0f"
[[package]]
name = "zerocopy"
version = "0.7.32"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
@@ -7435,9 +7515,9 @@ dependencies = [
[[package]]
name = "zerocopy-derive"
version = "0.7.32"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",

View File

@@ -78,7 +78,7 @@ num-derive = "0.4"
num-traits = { workspace = true }
parking_lot = "0.12.4"
percent-encoding = "2.3"
pgp = { version = "0.19.0", default-features = false }
pgp = { version = "0.19.0", features = ["draft-pqc"], default-features = false }
pin-project = "1"
qrcodegen = "1.7.0"
quick-xml = { version = "0.39", features = ["escape-html"] }

View File

@@ -43,7 +43,12 @@ ignore = [
# hickory-proto 0.25.2 quadratic complexity issue.
# Dependency of iroh 0.35.0, cannot be updated as of 2026-05-02.
# <https://rustsec.org/advisories/RUSTSEC-2026-0119>
"RUSTSEC-2026-0119"
"RUSTSEC-2026-0119",
# Timing side channel in ml-dsa dependency of rPGP.
# We enable PQC for encryption rather than signatures.
# <https://rustsec.org/advisories/RUSTSEC-2025-0144>
"RUSTSEC-2025-0144",
]
[bans]
@@ -62,6 +67,7 @@ skip = [
{ name = "getrandom", version = "0.2.12" },
{ name = "heck", version = "0.4.1" },
{ name = "http", version = "0.2.12" },
{ name = "hybrid-array", version = "0.2.3" },
{ name = "linux-raw-sys", version = "0.4.14" },
{ name = "lru", version = "0.12.5" },
{ name = "netlink-packet-route", version = "0.17.1" },

View File

@@ -1049,7 +1049,6 @@ async fn chatlist_len(ctx: &Context, listflags: usize) -> usize {
async fn test_archive() {
// create two chats
let t = TestContext::new_alice().await;
let mut msg = Message::new_text("foo".to_string());
let msg_id = add_device_msg(&t, None, Some(&mut msg)).await.unwrap();
let chat_id1 = message::Message::load_from_db(&t, msg_id)
@@ -1382,9 +1381,6 @@ async fn test_markfresh_chat() -> Result<()> {
async fn test_archive_fresh_msgs() -> Result<()> {
let t = TestContext::new_alice().await;
// FIXME: use encrypted messages
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
async fn msg_from(t: &TestContext, name: &str, num: u32) -> Result<()> {
receive_imf(
t,
@@ -1877,38 +1873,45 @@ async fn test_lookup_self_by_contact_id() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_marknoticed_chat() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;
let chat = alice.create_chat(bob).await;
let t = TestContext::new_alice().await;
let chat = t.create_chat_with_contact("bob", "bob@example.org").await;
let bob_chat_id = bob.create_chat_id(alice).await;
let sent = bob.send_text(bob_chat_id, "hello").await;
alice.recv_msg(&sent).await;
receive_imf(
&t,
b"From: bob@example.org\n\
To: alice@example.org\n\
Message-ID: <1@example.org>\n\
Chat-Version: 1.0\n\
Date: Fri, 23 Apr 2021 10:00:57 +0000\n\
\n\
hello\n",
false,
)
.await?;
let chats = Chatlist::try_load(alice, 0, None, None).await?;
let chats = Chatlist::try_load(&t, 0, None, None).await?;
assert_eq!(chats.len(), 1);
assert_eq!(chats.get_chat_id(0)?, chat.id);
assert_eq!(chat.id.get_fresh_msg_cnt(alice).await?, 1);
assert_eq!(alice.get_fresh_msgs().await?.len(), 1);
assert_eq!(chat.id.get_fresh_msg_cnt(&t).await?, 1);
assert_eq!(t.get_fresh_msgs().await?.len(), 1);
let msgs = get_chat_msgs(alice, chat.id).await?;
assert_eq!(msgs.len(), 2);
let msg_id = match msgs.last().unwrap() {
let msgs = get_chat_msgs(&t, chat.id).await?;
assert_eq!(msgs.len(), 1);
let msg_id = match msgs.first().unwrap() {
ChatItem::Message { msg_id } => *msg_id,
_ => MsgId::new_unset(),
};
let msg = message::Message::load_from_db(alice, msg_id).await?;
let msg = message::Message::load_from_db(&t, msg_id).await?;
assert_eq!(msg.state, MessageState::InFresh);
marknoticed_chat(alice, chat.id).await?;
marknoticed_chat(&t, chat.id).await?;
let chats = Chatlist::try_load(alice, 0, None, None).await?;
let chats = Chatlist::try_load(&t, 0, None, None).await?;
assert_eq!(chats.len(), 1);
let msg = message::Message::load_from_db(alice, msg_id).await?;
let msg = message::Message::load_from_db(&t, msg_id).await?;
assert_eq!(msg.state, MessageState::InNoticed);
assert_eq!(chat.id.get_fresh_msg_cnt(alice).await?, 0);
assert_eq!(alice.get_fresh_msgs().await?.len(), 0);
assert_eq!(chat.id.get_fresh_msg_cnt(&t).await?, 0);
assert_eq!(t.get_fresh_msgs().await?.len(), 0);
Ok(())
}
@@ -1916,7 +1919,6 @@ async fn test_marknoticed_chat() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_contact_request_fresh_messages() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
let chats = Chatlist::try_load(&t, 0, None, None).await?;
assert_eq!(chats.len(), 0);
@@ -1968,43 +1970,40 @@ async fn test_contact_request_fresh_messages() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_contact_request_archive() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;
let t = TestContext::new_alice().await;
let bob_chat_id = bob.create_chat_id(alice).await;
let bob_sent_text = bob.send_text(bob_chat_id, "hello").await;
alice.recv_msg(&bob_sent_text).await;
receive_imf(
&t,
b"From: bob@example.org\n\
To: alice@example.org\n\
Message-ID: <2@example.org>\n\
Chat-Version: 1.0\n\
Date: Sun, 22 Mar 2021 19:37:57 +0000\n\
\n\
hello\n",
false,
)
.await?;
let chats = Chatlist::try_load(alice, 0, None, None).await?;
let chats = Chatlist::try_load(&t, 0, None, None).await?;
assert_eq!(chats.len(), 1);
let chat_id = chats.get_chat_id(0)?;
assert!(
Chat::load_from_db(alice, chat_id)
.await?
.is_contact_request()
);
assert_eq!(get_archived_cnt(alice).await?, 0);
assert!(Chat::load_from_db(&t, chat_id).await?.is_contact_request());
assert_eq!(get_archived_cnt(&t).await?, 0);
// archive request without accepting or blocking
chat_id
.set_visibility(alice, ChatVisibility::Archived)
.await?;
chat_id.set_visibility(&t, ChatVisibility::Archived).await?;
let chats = Chatlist::try_load(alice, 0, None, None).await?;
let chats = Chatlist::try_load(&t, 0, None, None).await?;
assert_eq!(chats.len(), 1);
let chat_id = chats.get_chat_id(0)?;
assert!(chat_id.is_archived_link());
assert_eq!(get_archived_cnt(alice).await?, 1);
assert_eq!(get_archived_cnt(&t).await?, 1);
let chats = Chatlist::try_load(alice, DC_GCL_ARCHIVED_ONLY, None, None).await?;
let chats = Chatlist::try_load(&t, DC_GCL_ARCHIVED_ONLY, None, None).await?;
assert_eq!(chats.len(), 1);
let chat_id = chats.get_chat_id(0)?;
assert!(
Chat::load_from_db(alice, chat_id)
.await?
.is_contact_request()
);
assert!(Chat::load_from_db(&t, chat_id).await?.is_contact_request());
Ok(())
}
@@ -2012,9 +2011,6 @@ async fn test_contact_request_archive() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_classic_email_chat() -> Result<()> {
let alice = TestContext::new_alice().await;
alice
.set_config(Config::ProcessUnencrypted, Some("1"))
.await?;
// Alice receives a classic (non-chat) message from Bob.
receive_imf(

View File

@@ -473,7 +473,6 @@ mod tests {
add_contact_to_chat, create_broadcast, create_group, get_chat_contacts,
remove_contact_from_chat, send_text_msg, set_chat_name,
};
use crate::config::Config;
use crate::receive_imf::receive_imf;
use crate::securejoin::get_securejoin_qr;
use crate::stock_str::StockMessage;
@@ -666,7 +665,6 @@ mod tests {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_search_single_chat() -> anyhow::Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
// receive a one-to-one-message
receive_imf(
@@ -727,7 +725,6 @@ mod tests {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_search_single_chat_without_authname() -> anyhow::Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
// receive a one-to-one-message without authname set
receive_imf(

View File

@@ -486,11 +486,6 @@ pub enum Config {
/// Experimental option denoting that the current profile is shared between multiple team members.
/// For now, the only effect of this option is that seen flags are not synchronized.
TeamProfile,
/// Process unencrypted messages.
///
/// Unencrypted messages are fetched and processed only if this setting is explicitly enabled.
ProcessUnencrypted,
}
impl Config {

View File

@@ -1056,12 +1056,6 @@ impl Context {
"team_profile",
self.get_config_bool(Config::TeamProfile).await?.to_string(),
);
res.insert(
"process_unencrypted",
self.get_config_bool(Config::ProcessUnencrypted)
.await?
.to_string(),
);
let elapsed = time_elapsed(&self.creation_time);
res.insert("uptime", duration_to_str(elapsed));

View File

@@ -370,7 +370,6 @@ mod tests {
use super::*;
use crate::receive_imf::receive_imf;
use crate::test_utils::TestContext;
use crate::config::Config;
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mixed_up_mime() -> Result<()> {
@@ -403,7 +402,6 @@ mod tests {
assert!(get_attachment_mime(&mail).is_some());
let bob = TestContext::new_bob().await;
bob.set_config(Config::ProcessUnencrypted, Some("1")).await?;
receive_imf(&bob, attachment_mime, false).await?;
let msg = bob.get_last_msg().await;
// Subject should be prepended because the attachment doesn't have "Chat-Version".
@@ -418,7 +416,6 @@ mod tests {
// Desktop via MS Exchange (actually made with TB though).
let mixed_up_mime = include_bytes!("../test-data/message/mixed-up-long.eml");
let bob = TestContext::new_bob().await;
bob.set_config(Config::ProcessUnencrypted, Some("1")).await?;
receive_imf(&bob, mixed_up_mime, false).await?;
let msg = bob.get_last_msg().await;
assert!(!msg.get_text().is_empty());

View File

@@ -42,25 +42,12 @@ impl EncryptHelper {
compress: bool,
seipd_version: SeipdVersion,
) -> Result<String> {
let sign_key = load_self_secret_key(context).await?;
let mut raw_message = Vec::new();
let cursor = Cursor::new(&mut raw_message);
mail_to_encrypt.clone().write_part(cursor).ok();
let ctext = self
.encrypt_raw(context, keyring, raw_message, compress, seipd_version)
.await?;
Ok(ctext)
}
pub async fn encrypt_raw(
self,
context: &Context,
keyring: Vec<SignedPublicKey>,
raw_message: Vec<u8>,
compress: bool,
seipd_version: SeipdVersion,
) -> Result<String> {
let sign_key = load_self_secret_key(context).await?;
let ctext =
pgp::pk_encrypt(raw_message, keyring, sign_key, compress, seipd_version).await?;
@@ -160,8 +147,6 @@ Sent with my Delta Chat Messenger: https://delta.chat";
let mut tcm = TestContextManager::new();
let bob = &tcm.bob().await;
bob.set_config_bool(Config::IsChatmail, true).await?;
bob.set_config_bool(Config::ProcessUnencrypted, true)
.await?;
let bob_chat_id = receive_imf(
bob,
b"From: alice@example.org\n\

View File

@@ -287,7 +287,6 @@ impl MsgId {
mod tests {
use super::*;
use crate::chat::{self, Chat, forward_msgs, save_msgs};
use crate::config::Config;
use crate::constants;
use crate::contact::ContactId;
use crate::message::{MessengerMessage, Viewtype};
@@ -451,9 +450,6 @@ test some special html-characters as &lt; &gt; and &amp; but also &quot; and &#x
// alice receives a non-delta html-message
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
alice
.set_config(Config::ProcessUnencrypted, Some("1"))
.await?;
let chat = alice
.create_chat_with_contact("", "sender@testrun.org")
.await;
@@ -487,8 +483,6 @@ test some special html-characters as &lt; &gt; and &amp; but also &quot; and &#x
// bob: check that bob also got the html-part of the forwarded message
let bob = &tcm.bob().await;
bob.set_config(Config::ProcessUnencrypted, Some("1"))
.await?;
let chat_bob = bob.create_chat_with_contact("", "alice@example.org").await;
async fn check_receiver(ctx: &TestContext, chat: &Chat, sender: &TestContext) {
let msg = ctx.recv_msg(&sender.pop_sent_msg().await).await;
@@ -526,12 +520,8 @@ test some special html-characters as &lt; &gt; and &amp; but also &quot; and &#x
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_html_save_msg() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
alice
.set_config(Config::ProcessUnencrypted, Some("1"))
.await?;
// Alice receives a non-delta html-message
let alice = TestContext::new_alice().await;
let chat = alice
.create_chat_with_contact("", "sender@testrun.org")
.await;
@@ -565,10 +555,6 @@ test some special html-characters as &lt; &gt; and &amp; but also &quot; and &#x
let mut tcm = TestContextManager::new();
// Alice receives a non-delta html-message
let alice = &tcm.alice().await;
alice
.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
let chat = alice
.create_chat_with_contact("", "sender@testrun.org")
.await;
@@ -632,22 +618,18 @@ test some special html-characters as &lt; &gt; and &amp; but also &quot; and &#x
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_cp1252_html() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
alice
.set_config(Config::ProcessUnencrypted, Some("1"))
.await?;
let t = TestContext::new_alice().await;
receive_imf(
alice,
&t,
include_bytes!("../test-data/message/cp1252-html.eml"),
false,
)
.await?;
let msg = alice.get_last_msg().await;
let msg = t.get_last_msg().await;
assert_eq!(msg.viewtype, Viewtype::Text);
assert!(msg.text.contains("foo bar ä ö ü ß"));
assert!(msg.has_html());
let html = msg.get_id().get_html(alice).await?.unwrap();
let html = msg.get_id().get_html(&t).await?.unwrap();
println!("{html}");
assert!(html.contains("foo bar ä ö ü ß"));
Ok(())

View File

@@ -1996,21 +1996,12 @@ pub(crate) async fn prefetch_should_download(
// prevent_rename=true as this might be a mailing list message and in this case it would be bad if we rename the contact.
// (prevent_rename is the last argument of from_field_to_contact_id())
let is_encrypted = if let Some(content_type) = headers.get_header_value(HeaderDef::ContentType)
{
mailparse::parse_content_type(&content_type).mimetype == "multipart/encrypted"
} else {
false
};
if flags.any(|f| f == Flag::Draft) {
info!(context, "Ignoring draft message");
return Ok(false);
}
let should_download = maybe_ndn
|| (!blocked_contact
&& (is_encrypted || context.get_config_bool(Config::ProcessUnencrypted).await?));
let should_download = !blocked_contact || maybe_ndn;
Ok(should_download)
}

View File

@@ -21,7 +21,6 @@ const PREFETCH_FLAGS: &str = "(UID RFC822.SIZE BODY.PEEK[HEADER.FIELDS (\
DATE \
X-MICROSOFT-ORIGINAL-MESSAGE-ID \
FROM \
CONTENT-TYPE \
CHAT-VERSION \
CHAT-IS-POST-MESSAGE \
AUTOCRYPT-SETUP-MESSAGE\

View File

@@ -570,9 +570,11 @@ pub async fn preconfigure_keypair(context: &Context, secret_data: &str) -> Resul
pub struct Fingerprint(Vec<u8>);
impl Fingerprint {
/// Creates new 160-bit (20 bytes) fingerprint.
/// Creates new fingerprint.
///
/// It is 160-bit (20 bytes) for v4 keys and 32 bytes for v6 keys.
pub fn new(v: Vec<u8>) -> Fingerprint {
debug_assert_eq!(v.len(), 20);
debug_assert!(v.len() == 20 || v.len() == 32);
Fingerprint(v)
}

View File

@@ -871,7 +871,6 @@ mod tests {
use crate::config::Config;
use crate::message::MessageState;
use crate::receive_imf::receive_imf;
use crate::test_utils;
use crate::test_utils::{ExpectedEvents, TestContext, TestContextManager};
use crate::tools::SystemTime;
@@ -940,15 +939,12 @@ mod tests {
/// Tests that location.kml is hidden.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn receive_location_kml() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;
let alice = TestContext::new_alice().await;
let encrypted_message = test_utils::encrypt_raw_message(
bob,
&[alice],
receive_imf(
&alice,
br#"Subject: Hello
Message-ID: <hello@example.net>
Message-ID: hello@example.net
To: Alice <alice@example.org>
From: Bob <bob@example.net>
Date: Mon, 20 Dec 2021 00:00:00 +0000
@@ -956,15 +952,14 @@ Chat-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no
Text message."#,
false,
)
.await?;
receive_imf(alice, encrypted_message.as_bytes(), false).await?;
let received_msg = alice.get_last_msg().await;
assert_eq!(received_msg.text, "Text message.");
let encrypted_message = test_utils::encrypt_raw_message(
bob,
&[alice],
receive_imf(
&alice,
br#"Subject: locations
MIME-Version: 1.0
To: <alice@example.org>
@@ -991,8 +986,10 @@ Content-Disposition: attachment; filename="location.kml"
</Document>
</kml>
--U8BOG8qNXfB0GgLiQ3PKUjlvdIuLRF--"#).await?;
receive_imf(alice, encrypted_message.as_bytes(), false).await?;
--U8BOG8qNXfB0GgLiQ3PKUjlvdIuLRF--"#,
false,
)
.await?;
// Received location message is not visible, last message stays the same.
let received_msg2 = alice.get_last_msg().await;

View File

@@ -139,14 +139,23 @@ async fn test_unencrypted_quote_encrypted_message() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_chat_id() {
// Alice receives a message that pops up as a contact request
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;
let chat_id = bob.create_chat_id(alice).await;
let sent = bob.send_text(chat_id, "hello").await;
let msg = bob.recv_msg(&sent).await;
let alice = TestContext::new_alice().await;
receive_imf(
&alice,
b"From: Bob <bob@example.com>\n\
To: alice@example.org\n\
Chat-Version: 1.0\n\
Message-ID: <123@example.com>\n\
Date: Fri, 29 Jan 2021 21:37:55 +0000\n\
\n\
hello\n",
false,
)
.await
.unwrap();
// check chat-id of this message
let msg = alice.get_last_msg().await;
assert!(!msg.get_chat_id().is_special());
assert_eq!(msg.get_text(), "hello".to_string());
}
@@ -456,9 +465,7 @@ async fn test_get_state() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_is_bot() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
alice.set_config(Config::ProcessUnencrypted, Some("1")).await?;
let alice = TestContext::new_alice().await;
// Alice receives an auto-generated non-chat message.
//
@@ -466,7 +473,7 @@ async fn test_is_bot() -> Result<()> {
// in which case the message should be marked as bot-generated,
// but the contact should not.
receive_imf(
alice,
&alice,
b"From: Claire <claire@example.com>\n\
To: alice@example.org\n\
Message-ID: <789@example.com>\n\
@@ -485,7 +492,7 @@ async fn test_is_bot() -> Result<()> {
// Alice receives a message from Bob the bot.
receive_imf(
alice,
&alice,
b"From: Bob <bob@example.com>\n\
To: alice@example.org\n\
Chat-Version: 1.0\n\
@@ -505,7 +512,7 @@ async fn test_is_bot() -> Result<()> {
// Alice receives a message from Bob who is not the bot anymore.
receive_imf(
alice,
&alice,
b"From: Bob <bob@example.com>\n\
To: alice@example.org\n\
Chat-Version: 1.0\n\
@@ -519,7 +526,7 @@ async fn test_is_bot() -> Result<()> {
let msg = alice.get_last_msg().await;
assert_eq!(msg.get_text(), "hello again".to_string());
assert!(!msg.is_bot());
let contact = Contact::get_by_id(alice, msg.from_id).await?;
let contact = Contact::get_by_id(&alice, msg.from_id).await?;
assert!(!contact.is_bot());
Ok(())

View File

@@ -356,7 +356,7 @@ impl MimeMessage {
let decrypted_msg; // Decrypted signed OpenPGP message.
let expected_sender_fingerprint: Option<String>;
let (mail, is_encrypted) = match decrypt::decrypt(context, &mail).await {
let (mail, is_encrypted) = match Box::pin(decrypt::decrypt(context, &mail)).await {
Ok(Some((mut msg, expected_sender_fp))) => {
mail_raw = msg.as_data_vec().unwrap_or_default();

View File

@@ -1503,23 +1503,31 @@ Some reply
// Test that WantsMdn parameter is not set on outgoing messages.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_outgoing_wants_mdn() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let alice2 = &tcm.alice().await;
let bob = &tcm.bob().await;
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
let chat_id = alice.create_chat(bob).await.id;
let sent = alice.send_text(chat_id, "Message.").await;
let raw = br"Date: Thu, 28 Jan 2021 00:26:57 +0000
Chat-Version: 1.0\n\
Message-ID: <foobarbaz@example.org>
To: Bob <bob@example.org>
From: Alice <alice@example.org>
Subject: subject
Chat-Disposition-Notification-To: alice@example.org
Message.
";
// Bob receives message.
let bob_msg = bob.recv_msg(&sent).await;
receive_imf(&bob, raw, false).await?;
let msg = bob.get_last_msg().await;
// Message is incoming.
assert!(bob_msg.param.get_bool(Param::WantsMdn).unwrap());
assert!(msg.param.get_bool(Param::WantsMdn).unwrap());
// Alice receives copy-to-self.
let alice2_msg = alice2.recv_msg(&sent).await;
receive_imf(&alice, raw, false).await?;
let msg = alice.get_last_msg().await;
// Message is outgoing, don't send read receipt to self.
assert!(alice2_msg.param.get_bool(Param::WantsMdn).is_none());
assert!(msg.param.get_bool(Param::WantsMdn).is_none());
Ok(())
}
@@ -1596,9 +1604,7 @@ async fn test_ignore_read_receipt_to_self() -> Result<()> {
/// recognize it as MDN nevertheless to avoid displaying it in the chat as normal message.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_ms_exchange_mdn() -> Result<()> {
let mut tcm = TestContextManager::new();
let t = tcm.alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
let t = TestContext::new_alice().await;
let original =
include_bytes!("../../test-data/message/ms_exchange_report_original_message.eml");
@@ -2042,8 +2048,6 @@ async fn test_multiple_autocrypt_hdrs() -> Result<()> {
async fn test_receive_signed_only() -> Result<()> {
let mut tcm = TestContextManager::new();
let bob = &tcm.bob().await;
bob.set_config(Config::ProcessUnencrypted, Some("1"))
.await?;
let imf_raw = include_bytes!("../../test-data/message/unencrypted_signed_simple.eml");
let msg = receive_imf(bob, imf_raw, false).await?.unwrap();

View File

@@ -847,4 +847,21 @@ mod tests {
assert!(merge_openpgp_certificates(alice.clone(), bob.clone()).is_err());
assert!(merge_openpgp_certificates(bob.clone(), alice.clone()).is_err());
}
/// Test PQC support.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_pqc() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let pqc = &tcm.pqc().await;
let pqc_received_message = tcm.send_recv_accept(alice, pqc, "Hi!").await;
let pqc_chat_id = pqc_received_message.chat_id;
let pqc_sent = pqc.send_text(pqc_chat_id, "Hello back!").await;
let alice_rcvd = alice.recv_msg(&pqc_sent).await;
assert_eq!(alice_rcvd.text, "Hello back!");
Ok(())
}
}

View File

@@ -505,11 +505,6 @@ pub(crate) async fn receive_imf_inner(
Ok(mime_parser) => mime_parser,
};
if !(mime_parser.was_encrypted() || mime_parser.get_header(HeaderDef::SecureJoin).is_some()) && !context.get_config_bool(Config::ProcessUnencrypted).await? {
warn!(context, "Fetched unencrypted message, ignoring");
return trash().await;
}
let rfc724_mid_orig = &mime_parser
.get_rfc724_mid()
.unwrap_or(rfc724_mid.to_string());

View File

@@ -100,9 +100,6 @@ async fn test_adhoc_group_is_shown() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_adhoc_group_show_accepted_contact_accepted() {
let t = TestContext::new_alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true)
.await
.unwrap();
// accept Bob by accepting a delta-message from Bob
receive_imf(&t, MSGRMSG, false).await.unwrap();
@@ -157,9 +154,6 @@ async fn test_adhoc_group_show_all() {
async fn test_adhoc_groups_merge() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
alice
.set_config_bool(Config::ProcessUnencrypted, true)
.await?;
receive_imf(
alice,
b"From: bob@example.net\n\
@@ -360,9 +354,6 @@ async fn test_no_message_id_header() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_escaped_from() {
let t = TestContext::new_alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true)
.await
.unwrap();
let contact_id = Contact::create(&t, "foobar", "foobar@example.com")
.await
.unwrap();
@@ -396,9 +387,6 @@ async fn test_escaped_from() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_escaped_recipients() {
let t = TestContext::new_alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true)
.await
.unwrap();
Contact::create(&t, "foobar", "foobar@example.com")
.await
.unwrap();
@@ -446,9 +434,6 @@ async fn test_escaped_recipients() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_cc_to_contact() {
let t = TestContext::new_alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true)
.await
.unwrap();
Contact::create(&t, "foobar", "foobar@example.com")
.await
.unwrap();
@@ -605,9 +590,6 @@ async fn test_parse_ndn(
) -> (TestContext, MsgId) {
let t = TestContext::new().await;
t.configure_addr(self_addr).await;
t.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
receive_imf(
&t,
@@ -692,7 +674,6 @@ async fn test_resend_after_ndn() -> Result<()> {
async fn test_parse_ndn_group_msg() -> Result<()> {
let t = TestContext::new().await;
t.configure_addr("alice@gmail.com").await;
t.set_config_bool(Config::ProcessUnencrypted, true).await?;
receive_imf(
&t,
@@ -734,7 +715,6 @@ async fn test_parse_ndn_group_msg() -> Result<()> {
async fn test_concat_multiple_ndns() -> Result<()> {
let t = TestContext::new().await;
t.configure_addr("alice@posteo.org").await;
t.set_config_bool(Config::ProcessUnencrypted, true).await?;
let mid = "1234@mail.gmail.com";
receive_imf(
&t,
@@ -792,9 +772,6 @@ async fn load_imf_email(context: &Context, imf_raw: &[u8]) -> Message {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_html_only_mail() {
let t = TestContext::new_alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true)
.await
.unwrap();
let msg = load_imf_email(&t, include_bytes!("../../test-data/message/wrong-html.eml")).await;
assert_eq!(
msg.text,
@@ -830,7 +807,6 @@ static GH_MAILINGLIST2: &str = "Received: (Postfix, from userid 1000); Mon, 4 De
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_github_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true).await?;
receive_imf(&t.ctx, GH_MAILINGLIST, false).await?;
@@ -904,8 +880,6 @@ static DC_MAILINGLIST2: &[u8] = b"Received: (Postfix, from userid 1000); Mon, 4
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_classic_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
receive_imf(&t.ctx, DC_MAILINGLIST, false).await.unwrap();
let chats = Chatlist::try_load(&t.ctx, 0, None, None).await.unwrap();
let chat_id = chats.get_chat_id(0).unwrap();
@@ -947,8 +921,6 @@ Hello mailinglist!\r\n"
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_other_device_writes_to_mailinglist() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
receive_imf(&t, DC_MAILINGLIST, false).await.unwrap();
let first_msg = t.get_last_msg().await;
let first_chat = Chat::load_from_db(&t, first_msg.chat_id).await?;
@@ -999,9 +971,6 @@ async fn test_other_device_writes_to_mailinglist() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_block_mailing_list() {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
receive_imf(&t.ctx, DC_MAILINGLIST, false).await.unwrap();
t.evtracker.wait_next_incoming_message().await;
@@ -1036,9 +1005,6 @@ async fn test_block_mailing_list() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailing_list_decide_block_then_unblock() {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
receive_imf(&t, DC_MAILINGLIST, false).await.unwrap();
let blocked = Contact::get_all_blocked(&t).await.unwrap();
@@ -1069,9 +1035,6 @@ async fn test_mailing_list_decide_block_then_unblock() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailing_list_decide_not_now() {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
receive_imf(&t.ctx, DC_MAILINGLIST, false).await.unwrap();
@@ -1099,9 +1062,6 @@ async fn test_mailing_list_decide_not_now() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailing_list_decide_accept() {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
receive_imf(&t.ctx, DC_MAILINGLIST, false).await.unwrap();
@@ -1124,8 +1084,6 @@ async fn test_mailing_list_decide_accept() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailing_list_multiple_names_in_subject() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
receive_imf(
&t,
b"From: Foo Bar <foo@bar.org>\n\
@@ -1150,7 +1108,6 @@ async fn test_mailing_list_multiple_names_in_subject() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_majordomo_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
// test mailing lists not having a `ListId:`-header
receive_imf(
@@ -1203,7 +1160,6 @@ async fn test_majordomo_mailing_list() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailchimp_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
receive_imf(
&t,
@@ -1237,7 +1193,6 @@ async fn test_mailchimp_mailing_list() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_dhl_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
receive_imf(
&t,
@@ -1263,7 +1218,6 @@ async fn test_dhl_mailing_list() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_dpd_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
receive_imf(
&t,
@@ -1289,7 +1243,6 @@ async fn test_dpd_mailing_list() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_xt_local_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
receive_imf(
&t,
@@ -1323,7 +1276,6 @@ async fn test_xt_local_mailing_list() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_xing_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
receive_imf(
&t,
@@ -1346,7 +1298,6 @@ async fn test_xing_mailing_list() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_ttline_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
receive_imf(
&t,
@@ -1367,9 +1318,6 @@ async fn test_ttline_mailing_list() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailing_list_with_mimepart_footer() {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
// the mailing list message contains two top-level texts.
// the second text is a footer that is added by some mailing list software
@@ -1397,9 +1345,6 @@ async fn test_mailing_list_with_mimepart_footer() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailing_list_with_mimepart_footer_signed() {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
receive_imf(
&t,
@@ -1424,9 +1369,6 @@ async fn test_mailing_list_with_mimepart_footer_signed() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_apply_mailinglist_changes_assigned_by_reply() {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
receive_imf(&t, GH_MAILINGLIST, false).await.unwrap();
@@ -1465,9 +1407,6 @@ async fn test_apply_mailinglist_changes_assigned_by_reply() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailing_list_chat_message() {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
receive_imf(
&t,
@@ -1490,9 +1429,6 @@ async fn test_mailing_list_chat_message() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailing_list_bot() {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
t.set_config(Config::Bot, Some("1")).await.unwrap();
receive_imf(
@@ -1525,10 +1461,6 @@ async fn test_dont_show_noreply_in_contacts_list() {
async fn check_dont_show_in_contacts_list(addr: &str) {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
receive_imf(
&t,
format!(
@@ -1558,9 +1490,6 @@ YEAAAAAA!.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_pdf_filename_simple() {
let t = TestContext::new_alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true)
.await
.unwrap();
let msg = load_imf_email(
&t,
include_bytes!("../../test-data/message/pdf_filename_simple.eml"),
@@ -1581,9 +1510,6 @@ async fn test_pdf_filename_simple() {
async fn test_pdf_filename_continuation() {
// test filenames split across multiple header lines, see rfc 2231
let t = TestContext::new_alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true)
.await
.unwrap();
let msg = load_imf_email(
&t,
include_bytes!("../../test-data/message/pdf_filename_continuation.eml"),
@@ -1609,9 +1535,6 @@ async fn test_pdf_filename_continuation() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_many_images() {
let t = TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
receive_imf(
&t,
@@ -1632,9 +1555,6 @@ async fn test_many_images() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_in_reply_to() {
let t = TestContext::new().await;
t.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
t.configure_addr("bob@example.com").await;
// Receive message from Alice about group "foo".
@@ -1712,10 +1632,6 @@ async fn test_save_mime_headers_off() -> anyhow::Result<()> {
async fn check_alias_reply(from_dc: bool, chat_request: bool, group_request: bool) {
let mut tcm = TestContextManager::new();
let alice = tcm.alice().await;
alice
.set_config_bool(Config::ProcessUnencrypted, true)
.await
.unwrap();
// Claire, a customer, sends a support request
// to the alias address <support@example.org>.
@@ -1782,11 +1698,6 @@ async fn check_alias_reply(from_dc: bool, chat_request: bool, group_request: boo
let claire = tcm.unconfigured().await;
claire.configure_addr("claire@example.org").await;
claire
.set_config_bool(Config::ProcessUnencrypted, true)
.await
.unwrap();
receive_imf(&claire, claire_request.as_bytes(), false)
.await
.unwrap();
@@ -2001,7 +1912,6 @@ Message content",
async fn test_unencrypted_doesnt_goto_self_chat() -> Result<()> {
let mut tcm = TestContextManager::new();
let t = &tcm.alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
let mut chat_id = None;
for (i, to) in [
@@ -2083,10 +1993,6 @@ async fn test_no_smtp_job_for_self_chat() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_outgoing_classic_mail_creates_chat() {
let alice = TestContext::new_alice().await;
alice
.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
// Alice downloads outgoing classic email.
receive_imf(
@@ -2112,9 +2018,6 @@ Message content",
async fn test_duplicate_message() -> Result<()> {
// Test that duplicate messages are ignored based on the Message-ID
let alice = TestContext::new_alice().await;
alice
.set_config_bool(Config::ProcessUnencrypted, true)
.await?;
let bob_contact_id = Contact::add_or_lookup(
&alice,
@@ -2173,8 +2076,6 @@ Second signature";
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_ignore_footer_status_from_mailinglist() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true).await?;
let bob_id = Contact::add_or_lookup(
&t,
"",
@@ -2254,8 +2155,6 @@ Original signature updated",
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_ignore_old_status_updates() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true).await?;
let bob_id = Contact::add_or_lookup(
&t,
"",
@@ -2325,15 +2224,11 @@ sig thursday",
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_chat_assignment_private_classical_reply() {
let mut tcm = TestContextManager::new();
for outgoing_is_classical in &[true, false] {
let t = &tcm.alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true)
.await
.unwrap();
let t = TestContext::new_alice().await;
receive_imf(
t,
&t,
format!(
r#"Received: from mout.gmx.net (mout.gmx.net [212.227.17.22])
Subject: =?utf-8?q?single_reply-to?=
@@ -2375,7 +2270,7 @@ Message-ID: <Gr.eJ_llQIXf0K.buxmrnMmG0Y@gmx.de>"
assert_eq!(group_chat.name, "single reply-to");
receive_imf(
t,
&t,
format!(
r#"Subject: Re: single reply-to
To: "Alice" <alice@example.org>
@@ -2507,12 +2402,8 @@ Sent with my Delta Chat Messenger: https://delta.chat
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_chat_assignment_nonprivate_classical_reply() {
let mut tcm = TestContextManager::new();
for outgoing_is_classical in &[true, false] {
let t = &tcm.alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true)
.await
.unwrap();
let t = TestContext::new_alice().await;
receive_imf(
&t,
@@ -2557,7 +2448,7 @@ Message-ID: <Gr.eJ_llQIXf0K.buxmrnMmG0Y@gmx.de>"
// =============== Receive another outgoing message and check that it is put into the same chat ===============
receive_imf(
t,
&t,
format!(
r#"Received: from mout.gmx.net (mout.gmx.net [212.227.17.22])
Subject: Out subj
@@ -2767,7 +2658,6 @@ async fn test_read_receipts_dont_unmark_bots() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_gmx_forwarded_msg() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true).await?;
receive_imf(
&t,
@@ -3363,9 +3253,6 @@ async fn test_blocked_contact_creates_group() -> Result<()> {
async fn test_outgoing_undecryptable() -> Result<()> {
let alice = &TestContext::new().await;
alice.configure_addr("alice@example.org").await;
alice
.set_config(Config::ProcessUnencrypted, Some("1"))
.await?;
let raw = include_bytes!("../../test-data/message/thunderbird_with_autocrypt.eml");
receive_imf(alice, raw, false).await?;
@@ -3402,7 +3289,6 @@ async fn test_outgoing_undecryptable() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_thunderbird_autocrypt() -> Result<()> {
let t = TestContext::new_bob().await;
t.set_config_bool(Config::ProcessUnencrypted, true).await?;
let raw = include_bytes!("../../test-data/message/thunderbird_with_autocrypt.eml");
let received_msg = receive_imf(&t, raw, false).await?.unwrap();
@@ -3450,7 +3336,6 @@ async fn test_issuer_fingerprint() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_prefer_encrypt_mutual_if_encrypted() -> Result<()> {
let t = TestContext::new_bob().await;
t.set_config_bool(Config::ProcessUnencrypted, true).await?;
// The message has public key attached *and* Autocrypt header.
//
@@ -3522,9 +3407,6 @@ async fn test_forged_from_and_no_valid_signatures() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_wrong_from_name_and_no_valid_signatures() -> Result<()> {
let t = &TestContext::new_bob().await;
// TODO: same test, but with ProcessUnencrypted, should trash the message
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
let raw = include_bytes!("../../test-data/message/thunderbird_encrypted_signed.eml");
let raw = String::from_utf8(raw.to_vec())?.replace("From: Alice", "From: A");
receive_imf(t, raw.as_bytes(), false).await?.unwrap();
@@ -3539,8 +3421,6 @@ async fn test_wrong_from_name_and_no_valid_signatures() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_thunderbird_autocrypt_unencrypted() -> Result<()> {
let bob = &TestContext::new_bob().await;
bob.set_config(Config::ProcessUnencrypted, Some("1"))
.await?;
// Thunderbird message with Autocrypt header and a signature,
// but not encrypted.
@@ -3579,11 +3459,6 @@ async fn test_thunderbird_autocrypt_unencrypted() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_thunderbird_unsigned() -> Result<()> {
let alice = TestContext::new_alice().await;
// TODO: same test without process unencrypted should trash the message
alice
.set_config(Config::ProcessUnencrypted, Some("1"))
.await
.unwrap();
// Alice receives an unsigned message from Bob.
let raw = include_bytes!("../../test-data/message/thunderbird_encrypted_unsigned.eml");
@@ -3693,7 +3568,6 @@ async fn test_big_forwarded_with_big_attachment() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mua_user_adds_member() -> Result<()> {
let t = TestContext::new_alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true).await?;
receive_imf(
&t,
@@ -3745,9 +3619,6 @@ async fn test_mua_user_adds_member() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mua_user_adds_recipient_to_single_chat() -> Result<()> {
let alice = TestContext::new_alice().await;
alice
.set_config_bool(Config::ProcessUnencrypted, true)
.await?;
// Alice sends a 1:1 message to Bob, creating a 1:1 chat.
let msg = receive_imf(
@@ -4180,9 +4051,6 @@ async fn test_dont_readd_with_normal_msg() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mua_cant_remove() -> Result<()> {
let alice = TestContext::new_alice().await;
alice
.set_config_bool(Config::ProcessUnencrypted, true)
.await?;
let now = time();
@@ -4275,9 +4143,6 @@ async fn test_mua_cant_remove() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mua_can_add() -> Result<()> {
let alice = TestContext::new_alice().await;
alice
.set_config(Config::ProcessUnencrypted, Some("1"))
.await?;
let now = time();
@@ -4337,9 +4202,6 @@ async fn test_mua_can_add() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mua_can_readd() -> Result<()> {
let alice = TestContext::new_alice().await;
alice
.set_config_bool(Config::ProcessUnencrypted, true)
.await?;
// Alice creates chat with 3 contacts.
let msg = receive_imf(
@@ -4503,10 +4365,6 @@ async fn test_keep_member_list_if_possibly_nomember() -> Result<()> {
async fn test_adhoc_grp_name_no_prefix() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
alice
.set_config(Config::ProcessUnencrypted, Some("1"))
.await?;
let chat_id = receive_imf(
alice,
b"Subject: Re: Once upon a time this was with the only Re: here\n\
@@ -4542,12 +4400,12 @@ async fn test_outgoing_msg_forgery() -> Result<()> {
imex(alice, ImexMode::ExportSelfKeys, export_dir.path(), None).await?;
// We need Bob only to encrypt the forged message to Alice's key, actually Bob doesn't
// participate in the scenario.
let bob = &tcm.unconfigured().await;
let bob = &TestContext::new().await;
assert_eq!(crate::key::load_self_secret_keyring(bob).await?.len(), 0);
bob.configure_addr("bob@example.net").await;
imex(bob, ImexMode::ImportSelfKeys, export_dir.path(), None).await?;
assert_eq!(crate::key::load_self_secret_keyring(bob).await?.len(), 1);
let malice = &tcm.unconfigured().await;
let malice = &TestContext::new().await;
malice.configure_addr(alice_addr).await;
let malice_chat_id = tcm
@@ -4789,7 +4647,6 @@ async fn test_forged_from() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_multiline_iso_8859_1_subject() -> Result<()> {
let t = &TestContext::new_alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true).await?;
let mail = b"Received: (Postfix, from userid 1000); Mon, 4 Dec 2006 14:51:39 +0100 (CET)\n\
From: bob@example.com\n\
To: alice@example.org, claire@example.com\n\
@@ -4854,7 +4711,6 @@ async fn test_references() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_list_from() -> Result<()> {
let t = &TestContext::new_alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true).await?;
let raw = include_bytes!("../../test-data/message/list-from.eml");
let received = receive_imf(t, raw, false).await?.unwrap();
@@ -4984,7 +4840,6 @@ async fn test_make_n_send_vcard() -> Result<()> {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_unencrypted_group_id_no_recipients() -> Result<()> {
let t = &TestContext::new_alice().await;
t.set_config(Config::ProcessUnencrypted, Some("1")).await?;
let raw = "From: alice@example.org
Subject: Group
Chat-Version: 1.0
@@ -5458,9 +5313,6 @@ async fn test_outgoing_unencrypted_chat_assignment() {
async fn test_incoming_reply_with_date_in_past() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
alice
.set_config_bool(Config::ProcessUnencrypted, true)
.await?;
let msg0 = receive_imf(
alice,
@@ -5602,11 +5454,6 @@ async fn test_small_unencrypted_group() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;
alice
.set_config(Config::ProcessUnencrypted, Some("1"))
.await?;
bob.set_config(Config::ProcessUnencrypted, Some("1"))
.await?;
let alice_chat_id = chat::create_group_unencrypted(alice, "Unencrypted group").await?;
let alice_bob_id = alice.add_or_lookup_address_contact_id(bob).await;
@@ -5686,7 +5533,6 @@ async fn test_lookup_key_contact_by_address_self() -> Result<()> {
async fn test_calendar_alternative() -> Result<()> {
let mut tcm = TestContextManager::new();
let t = &tcm.alice().await;
t.set_config_bool(Config::ProcessUnencrypted, true).await?;
let raw = include_bytes!("../../test-data/message/calendar-alternative.eml");
let msg = receive_imf(t, raw, false).await?.unwrap();
assert_eq!(msg.msg_ids.len(), 1);

View File

@@ -772,9 +772,6 @@ fn manipulate_qr(v3: bool, remove_invite: bool, qr: &mut String) {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_adhoc_group_no_qr() -> Result<()> {
let alice = TestContext::new_alice().await;
alice
.set_config_bool(Config::ProcessUnencrypted, true)
.await?;
let mime = br#"Subject: First thread
Message-ID: first@example.org
@@ -1418,9 +1415,6 @@ async fn test_vc_request_encrypted_at_rest() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;
alice
.set_config_bool(Config::ProcessUnencrypted, true)
.await?;
let qr = get_securejoin_qr(alice, None).await?;

View File

@@ -20,7 +20,6 @@ use pretty_assertions::assert_eq;
use tempfile::{TempDir, tempdir};
use tokio::runtime::Handle;
use tokio::{fs, task};
use uuid::Uuid;
use crate::chat::{
self, Chat, ChatId, ChatIdBlocked, MessageListOptions, add_to_chat_contacts_table, create_group,
@@ -33,14 +32,12 @@ use crate::contact::{
Contact, ContactId, Modifier, Origin, import_vcard, make_vcard, mark_contact_id_as_verified,
};
use crate::context::Context;
use crate::e2ee::EncryptHelper;
use crate::events::{Event, EventEmitter, EventType, Events};
use crate::key::{self, DcKey, self_fingerprint};
use crate::log::warn;
use crate::login_param::EnteredLoginParam;
use crate::message::{Message, MessageState, MsgId, update_msg_state};
use crate::mimeparser::{MimeMessage, SystemMessage};
use crate::pgp::SeipdVersion;
use crate::receive_imf::receive_imf;
use crate::securejoin::{get_securejoin_qr, join_securejoin};
use crate::smtp::msg_has_pending_smtp_job;
@@ -140,6 +137,17 @@ impl TestContextManager {
.await
}
/// Returns a new "device" with a preconfigured v6 PQC key.
pub async fn pqc(&mut self) -> TestContext {
TestContext::builder()
.with_key_pair(pqc_keypair())
.with_address("pqc@example.org".to_string())
.with_id_offset(7000)
.with_log_sink(self.log_sink.clone())
.build(Some(&mut self.used_names))
.await
}
/// Creates a new unconfigured test account.
pub async fn unconfigured(&mut self) -> TestContext {
TestContext::builder()
@@ -307,6 +315,9 @@ impl TestContextManager {
pub struct TestContextBuilder {
key_pair: Option<SignedSecretKey>,
/// Email address.
address: Option<String>,
/// Log sink if set.
///
/// If log sink is not set,
@@ -331,6 +342,7 @@ impl TestContextBuilder {
/// This is a shortcut for `.with_key_pair(alice_keypair())`.
pub fn configure_alice(self) -> Self {
self.with_key_pair(alice_keypair())
.with_address("alice@example.org".to_string())
}
/// Configures as bob@example.net with fixed secret key.
@@ -338,6 +350,7 @@ impl TestContextBuilder {
/// This is a shortcut for `.with_key_pair(bob_keypair())`.
pub fn configure_bob(self) -> Self {
self.with_key_pair(bob_keypair())
.with_address("bob@example.net".to_string())
}
/// Configures as charlie@example.net with fixed secret key.
@@ -345,6 +358,7 @@ impl TestContextBuilder {
/// This is a shortcut for `.with_key_pair(charlie_keypair())`.
pub fn configure_charlie(self) -> Self {
self.with_key_pair(charlie_keypair())
.with_address("charlie@example.net".to_string())
}
/// Configures as dom@example.net with fixed secret key.
@@ -352,6 +366,7 @@ impl TestContextBuilder {
/// This is a shortcut for `.with_key_pair(dom_keypair())`.
pub fn configure_dom(self) -> Self {
self.with_key_pair(dom_keypair())
.with_address("dom@example.net".to_string())
}
/// Configures as elena@example.net with fixed secret key.
@@ -359,6 +374,7 @@ impl TestContextBuilder {
/// This is a shortcut for `.with_key_pair(elena_keypair())`.
pub fn configure_elena(self) -> Self {
self.with_key_pair(elena_keypair())
.with_address("elena@example.net".to_string())
}
/// Configures as fiona@example.net with fixed secret key.
@@ -366,6 +382,7 @@ impl TestContextBuilder {
/// This is a shortcut for `.with_key_pair(fiona_keypair())`.
pub fn configure_fiona(self) -> Self {
self.with_key_pair(fiona_keypair())
.with_address("fiona@example.net".to_string())
}
/// Configures the new [`TestContext`] with the provided [`SignedSecretKey`].
@@ -377,6 +394,12 @@ impl TestContextBuilder {
self
}
/// Sets email address.
pub fn with_address(mut self, address: String) -> Self {
self.address = Some(address);
self
}
/// Attaches a [`LogSink`] to this [`TestContext`].
///
/// This is useful when using multiple [`TestContext`] instances in one test: it allows
@@ -399,16 +422,7 @@ impl TestContextBuilder {
/// Builds the [`TestContext`].
pub async fn build(self, used_names: Option<&mut BTreeSet<String>>) -> TestContext {
if let Some(key_pair) = self.key_pair {
let userid = {
let public_key = key_pair.to_public_key();
let id_bstr = public_key.details.users.first().unwrap().id.id();
String::from_utf8(id_bstr.to_vec()).unwrap()
};
let addr = mailparse::addrparse(&userid)
.unwrap()
.extract_single_info()
.unwrap()
.addr;
let addr = self.address.expect("Address is not set").clone();
let name = EmailAddress::new(&addr).unwrap().local;
let mut unused_name = name.clone();
@@ -1217,53 +1231,6 @@ ORDER BY id"
}
}
pub async fn encrypt_raw_message(
context: &Context,
receivers: &[&TestContext],
payload: &[u8],
) -> Result<String> {
let encryption_helper = EncryptHelper::new(context).await?;
let mut encryption_keyring = vec![encryption_helper.public_key.clone()];
for receiver in receivers {
encryption_keyring.push(key::load_self_public_key(receiver).await?);
}
let from = context.get_primary_self_addr().await?;
let compress = false;
let encrypted_payload = encryption_helper
.encrypt_raw(
context,
encryption_keyring,
payload.to_vec(),
compress,
SeipdVersion::V2,
)
.await?;
let boundary = Uuid::new_v4();
let res = format!(
"Content-Type: multipart/encrypted; protocol=\"application/pgp-encrypted\"; boundary=\"{boundary}\"\r
MIME-Version: 1.0\r
From: {from}\r
Subject: [...]\r
\r
\r
--{boundary}
Content-Type: application/pgp-encrypted\r
\r
Version: 1\r
\r
--{boundary}\r
Content-Type: application/octet-stream\r
\r
{encrypted_payload}
\r
--{boundary}--
");
Ok(res)
}
impl Deref for TestContext {
type Target = Context;
@@ -1470,6 +1437,13 @@ pub fn fiona_keypair() -> SignedSecretKey {
key::SignedSecretKey::from_asc(include_str!("../test-data/key/fiona-secret.asc")).unwrap()
}
/// Loads a pre-generated v6 PQC keypair from disk.
///
/// Like [alice_keypair] but a different key and identity.
pub fn pqc_keypair() -> SignedSecretKey {
key::SignedSecretKey::from_asc(include_str!("../test-data/key/pqc-secret.asc")).unwrap()
}
/// Utility to help wait for and retrieve events.
///
/// This buffers the events in order they are emitted. This allows consuming events in

View File

@@ -332,7 +332,6 @@ async fn test_reply() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = tcm.alice().await;
let bob = tcm.bob().await;
alice.set_config(Config::ProcessUnencrypted, Some("1")).await?;
if verified {
mark_as_verified(&alice, &bob).await;

View File

@@ -983,7 +983,7 @@ async fn test_pop_status_update() -> Result<()> {
async fn test_draft_and_send_webxdc_status_update() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
let alice_chat_id = alice.create_chat(&bob).await.id;
let alice_chat_id = alice.create_email_chat(&bob).await.id;
// prepare webxdc instance,
// status updates are not sent for drafts, therefore send_webxdc_status_update() returns Ok(None)
@@ -1030,6 +1030,8 @@ async fn test_draft_and_send_webxdc_status_update() -> Result<()> {
let bob_instance = bob.recv_msg(&sent1).await;
assert_eq!(bob_instance.viewtype, Viewtype::Webxdc);
assert_eq!(bob_instance.get_filename().unwrap(), "minimal.xdc");
assert!(sent1.payload().contains("Content-Type: application/json"));
assert!(sent1.payload().contains("status-update.json"));
assert_eq!(
bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0))
.await?,

View File

@@ -0,0 +1,39 @@
-----BEGIN PGP PRIVATE KEY BLOCK-----
xUsGaf8NSRsAAAAgYy+GaofURMeV0+bcZZGY2ZdAamU+LG69ONjd3haVU3cAhm6G
IT/UEgFgVdPEhiXER9cfPLiCgkiw/L5mrAZfuLfCqgYfGwgAAABLBQJp/w1JIiEG
hys0q6D+DFWPnwQoWtuX0mL6ovH2kCjWmDufAFmB0+QCGwMCHgkECwkIBwYVCg4J
CAwBFg0nCQIIAgcCCQEIAQcBAAAAAEGQEO9Py9Q7njj1WXhtn1wMJSLBdHBE+qQu
RaCaiWkY5l4EWLlVRPAjX2bBSGq6n3+M+H6oFpOHETAX8IcFSxc260UD+PM0jQpV
H6ReNy7PBCQKx8RrBmn/DUkjAAAEwPmkVcPy1ye0/7D9nDQCkENUGry97iLkpcw/
tLJfzL5gJAdzrPkDkyukHxrO7kiUx+mzpiGZRZeyRgBd5YQ+mTgGrptxXLFHcKFR
79Fjg1UjgHEFjxCkCHUfnNcGZVM3p5skESnNgzsgFGiODfKhM4ew3AFgkUc5LNZj
Zgpgt4ETIhylbLUY89ccfNpKnQeJl3cv8lvA/yqhoUutJXwZQ/qYKFnEIGEBTFto
hLZn0KauF9KYOYvOV4yjeZQBlxSPNAWj9SqSNcalpTUFzwoQVSsqWwiys1PEzGAu
twQVKsZ3e/hlZAyR4eGMiYEmCEy7qjuaOJsqHQuW7hdOHWdVRUpRHOtfj3QAzdc0
CehVbyCRJVwnTSKiT3AYsdACH8U7mhI5/VxeSHNRIDN1Y6g6N5sx6Wur/HuKGFwx
L4urdPdpJJgyLXR8GUkL/yeqUhogu4mbVAmULbq2BCIKFNpMyGdhnDugN6Sp5MWc
GOxCW7CASuBYPHW/rto0C4M/3gCtN2sPtRAhOsXNBBhMqLlzzCgawulCiGtNjHUK
HsVhghgYwKRBT7vLSKDNsCVizzoZxNQq8yUEXpFIRsTGt3wYoigZn4wOSpmQbxGe
P3Uc2GWuuukCBNEP5oW4+TCFaNw5mvZgZwl5n4K34poxVgpqBIM2m2fEu8oyLPJZ
bBxnbty3MUAdLpxv+0otGSHJF4xa3lsEyUdr6+JZZXohNXKoyjeJMGo6qPkvCADI
upMnDSYZeLU5bVstHWS6otuRMEcjdLBkYfqfzBhkzbptscaUXzsaK4cd/iQzAA1r
A0ygvcA78Vo363cElNAJh3lntrZZGpBYnzcU/zLACKAVJCYPy3Cj8Al8x+gHP0Yr
ZSOYdZA1q9s2Kuqk7upCpcYDZ+uXGZs3ubA0TYCcO3FKhAwLhzJad5WApBFETYt2
3KJEwgEjQaCs7sNNiwaKxhLC2VJhUckgluGs5iUu9ck5jdU+N9MqTmloF/u2Gok8
QEqF9+DBhPg/fJoI9sN8sIyLrksEUQsm59mvJbVWOpxtbwpWZ+J4cat4azHE0khy
rolL6lZqDJYW4xVeoAVl5iccicjE6mJLemoxf6iJdohi5cN5JXyZtgtdsbIesJib
BLPJVahmv5W1Q4RmrwEp5Ua4xra5Mcac4PeINTOkGMErIhdvnuxEH/Cxd8VKhNlU
vdty4MOyUOkRRPhOMNKUyTkwS9yjprK3QbhEJgrJygHCGpQ0jwp9PrtKqNnOONSX
t4ZORuiAYHDFz3DPlJhLLzNoAJse0RAyolkPThoMl2JlY5ci8pVHb+Ed/kaeFxnE
UJJIOZvDFfNCFCM5CCXG/2pi/icA7nHPDFVBeYPMz1B5vrgmdDNMMFVQNMBtrroT
4pi1N5U4+EAv1vah40akQ/iFcfZjt4sE/jG0M0NCWqHBDPO7e0ae+2IqnIJmsHjL
N1ak3egY00CnRHdrPCkOkhooFIHA1hYxIwyP07qfkhUBNwSqZ4AfF8UW/nuLjeaj
ajEWz3zGLvQpfHSobEGPQKk+eIA1fOVeAuJAUAmJz5YO1Dk4OfczeQqQiOhtv+qe
PYaZQfBFJVamGocDHomPQkP/IvAJhuO9xWPapqbdRwGfVRJZgGsAy89mT1w0PU1C
u6VpIoyZB2J9LZkw9qb9sRRJAr2gpWGBD4CCmPZ8d17ZGDcIr8o+eI+bo5eKf+1j
6NhsjM7AmIccStNxZYWE4ZucvYYbPvT3ns/TNa7BH2DBqfGK84PawosGGBsIAAAA
LAUCaf8NSQIbDCIhBocrNKug/gxVj58EKFrbl9Ji+qLx9pAo1pg7nwBZgdPkAAAA
ADrcEIqnwTwJoiZAxzK+w7uQFHzsYMWIj8x+DKsn7D1silKINHDnFSrlSKRtbAW6
x9+HrN/nvR7bOnXZvZhz7lQ3Lp3YUdzEcqRMj8BWW8IXdm0C
-----END PGP PRIVATE KEY BLOCK-----