diff --git a/src/imex.rs b/src/imex.rs index 236f5e6fcc..16f9231f3a 100644 --- a/src/imex.rs +++ b/src/imex.rs @@ -808,6 +808,7 @@ mod tests { use tokio::task; use super::*; + use crate::key; use crate::pgp::{split_armored_data, HEADER_AUTOCRYPT, HEADER_SETUPCODE}; use crate::stock_str::StockMessage; use crate::test_utils::{alice_keypair, TestContext}; @@ -920,6 +921,37 @@ mod tests { } } + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_import_second_key() -> Result<()> { + let alice = &TestContext::new_alice().await; + let chat = alice.create_chat(alice).await; + let sent = alice.send_text(chat.id, "Encrypted with old key").await; + let export_dir = tempfile::tempdir().unwrap(); + + let alice = &TestContext::new().await; + alice.configure_addr("alice@example.org").await; + imex(alice, ImexMode::ExportSelfKeys, export_dir.path(), None).await?; + + let alice = &TestContext::new_alice().await; + let old_key = key::load_self_secret_key(alice).await?; + + imex(alice, ImexMode::ImportSelfKeys, export_dir.path(), None).await?; + + let new_key = key::load_self_secret_key(alice).await?; + assert_ne!(new_key, old_key); + assert_eq!( + key::load_self_secret_keyring(alice).await?, + vec![new_key, old_key] + ); + + let msg = alice.recv_msg(&sent).await; + assert!(msg.get_showpadlock()); + assert_eq!(msg.chat_id, alice.get_self_chat().await.id); + assert_eq!(msg.get_text(), "Encrypted with old key"); + + Ok(()) + } + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_export_and_import_backup() -> Result<()> { for set_verified_oneonone_chats in [true, false] { diff --git a/src/key.rs b/src/key.rs index 230f00f8cf..365726a375 100644 --- a/src/key.rs +++ b/src/key.rs @@ -16,6 +16,7 @@ use tokio::runtime::Handle; use crate::config::Config; use crate::constants::KeyGenType; use crate::context::Context; +use crate::log::LogExt; use crate::pgp::KeyPair; use crate::tools::{time, EmailAddress}; @@ -125,6 +126,25 @@ pub(crate) async fn load_self_secret_key(context: &Context) -> Result Result> { + let keys = context + .sql + .query_map( + r#"SELECT private_key + FROM keypairs + WHERE addr=(SELECT value FROM config WHERE keyname="configured_addr") + ORDER BY is_default DESC"#, + (), + |row| row.get::<_, Vec>(0), + |keys| keys.collect::, _>>().map_err(Into::into), + ) + .await? + .into_iter() + .filter_map(|bytes| SignedSecretKey::from_slice(&bytes).log_err(context).ok()) + .collect(); + Ok(keys) +} + impl DcKey for SignedPublicKey { fn to_asc(&self, header: Option<(&str, &str)>) -> String { // Not using .to_armored_string() to make clear *why* it is diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 7bf7bd4318..dc89782353 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -27,7 +27,7 @@ use crate::decrypt::{ use crate::dehtml::dehtml; use crate::events::EventType; use crate::headerdef::{HeaderDef, HeaderDefMap}; -use crate::key::{load_self_secret_key, DcKey, Fingerprint, SignedPublicKey}; +use crate::key::{load_self_secret_keyring, DcKey, Fingerprint, SignedPublicKey}; use crate::message::{ self, set_msg_failed, update_msg_state, Message, MessageState, MsgId, Viewtype, }; @@ -264,9 +264,7 @@ impl MimeMessage { headers.remove("chat-verified"); let from = from.context("No from in message")?; - let private_keyring = vec![load_self_secret_key(context) - .await - .context("Failed to get own key")?]; + let private_keyring = load_self_secret_keyring(context).await?; let mut decryption_info = prepare_decryption(context, &mail, &from.addr, message_time).await?;