diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 82098cb35..ae4a0b337 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -861,7 +861,12 @@ pub unsafe extern "C" fn dc_get_contact_encrinfo( assert!(!context.is_null()); let context = &*context; - Contact::get_encrinfo(context, contact_id).strdup() + Contact::get_encrinfo(context, contact_id) + .map(|s| s.strdup()) + .unwrap_or_else(|e| { + error!(context, 0, "{}", e); + std::ptr::null_mut() + }) } #[no_mangle] diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index b30f1e763..8aea771f2 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -1091,7 +1091,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E let mut res = format!("Contact info for: {}:\n\n", name_n_addr); - res += &Contact::get_encrinfo(context, contact_id); + res += &Contact::get_encrinfo(context, contact_id)?; let chatlist = Chatlist::try_load(context, 0, None, Some(contact_id))?; let chatlist_cnt = chatlist.len(); diff --git a/src/contact.rs b/src/contact.rs index 30d4ed42c..8ab3073b7 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -584,7 +584,12 @@ impl<'a> Contact<'a> { .unwrap_or_else(|_| std::ptr::null_mut()) } - pub fn get_encrinfo(context: &Context, contact_id: u32) -> String { + /// Returns a textual summary of the encryption state for the contact. + /// + /// This function returns a string explaining the encryption state + /// of the contact and if the connection is encrypted the + /// fingerprints of the keys involved. + pub fn get_encrinfo(context: &Context, contact_id: u32) -> Result { let mut ret = String::new(); if let Ok(contact) = Contact::load_from_db(context, contact_id) { @@ -603,7 +608,7 @@ impl<'a> Contact<'a> { }); ret += &p; if self_key.is_none() { - unsafe { dc_ensure_secret_key_exists(context) }; + dc_ensure_secret_key_exists(context)?; self_key = Key::from_self_public(context, &loginparam.addr, &context.sql); } let p = context.stock_str(StockMessage::FingerPrints); @@ -646,7 +651,7 @@ impl<'a> Contact<'a> { } } - ret + Ok(ret) } /// Delete a contact. The contact is deleted from the local device. It may happen that this is not diff --git a/src/dc_configure.rs b/src/dc_configure.rs index 73f449e7b..db4ed5a4e 100644 --- a/src/dc_configure.rs +++ b/src/dc_configure.rs @@ -101,7 +101,7 @@ pub fn dc_stop_ongoing_process(context: &Context) { } // the other dc_job_do_DC_JOB_*() functions are declared static in the c-file -#[allow(non_snake_case)] +#[allow(non_snake_case, unused_must_use)] pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_job_t) { let flags: libc::c_int; let mut current_block: u64; diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index db0c15a89..047203aa6 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -16,10 +16,12 @@ use mmime::mmapstring::*; use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR}; use crate::aheader::*; +use crate::config::Config; use crate::context::Context; use crate::dc_mimeparser::*; use crate::dc_securejoin::*; use crate::dc_tools::*; +use crate::error::*; use crate::key::*; use crate::keyring::*; use crate::peerstate::*; @@ -1045,33 +1047,53 @@ pub unsafe fn dc_e2ee_thanks(helper: &mut dc_e2ee_helper_t) { helper.cdata_to_free = 0 as *mut libc::c_void; } -/* makes sure, the private key exists, needed only for exporting keys and the case no message was sent before */ -// TODO should return bool /rtn -pub unsafe fn dc_ensure_secret_key_exists(context: &Context) -> libc::c_int { - /* normally, the key is generated as soon as the first mail is send - (this is to gain some extra-random-seed by the message content and the timespan between program start and message sending) */ - let mut success: libc::c_int = 0i32; - - let self_addr = context.sql.get_config(context, "configured_addr"); - if self_addr.is_none() { - warn!( - context, - 0, "Cannot ensure secret key if context is not configured.", - ); - } else if load_or_generate_self_public_key(context, self_addr.unwrap(), 0 as *mut mailmime) - .is_some() - { - /*no random text data for seeding available*/ - success = 1; +/// Ensures a private key exists for the configured user. +/// +/// Normally the private key is generated when the first message is +/// sent (allowing the use of some extra random seed from the message +/// content) but in a few locations there are no such guarantees, +/// e.g. when exporting keys, and calling this function ensures a +/// private key will be present. +/// +/// If this succeeds you are also guaranteed that the +/// [Config::ConfiguredAddr] is configured, this address is returned. +pub fn dc_ensure_secret_key_exists(context: &Context) -> Result { + let self_addr = context + .get_config(Config::ConfiguredAddr) + .ok_or(format_err!(concat!( + "Failed to get self address, ", + "cannot ensure secret key if not configured." + )))?; + unsafe { + load_or_generate_self_public_key(context, &self_addr, 0 as *mut mailmime) + .ok_or(format_err!("Failed to generate private key."))?; } - - success + Ok(self_addr) } #[cfg(test)] mod tests { use super::*; + use crate::test_utils::*; + + mod ensure_secret_key_exists { + use super::*; + + #[test] + fn test_prexisting() { + let t = dummy_context(); + let test_addr = configure_alice_keypair(&t.ctx); + assert_eq!(dc_ensure_secret_key_exists(&t.ctx).unwrap(), test_addr); + } + + #[test] + fn test_not_configured() { + let t = dummy_context(); + assert!(dc_ensure_secret_key_exists(&t.ctx).is_err()); + } + } + #[test] fn test_mailmime_parse() { let plain = b"Chat-Disposition-Notification-To: holger@deltachat.de diff --git a/src/dc_imex.rs b/src/dc_imex.rs index 259c7237d..2e767a5ce 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -194,20 +194,15 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char { setup_code.strdup() } +/// Renders HTML body of a setup file message. +/// +/// The `passphrase` must be at least 2 characters long. pub fn dc_render_setup_file(context: &Context, passphrase: &str) -> Result { ensure!( passphrase.len() >= 2, "Passphrase must be at least 2 chars long." ); - unsafe { - ensure!( - !(dc_ensure_secret_key_exists(context) == 0), - "No secret key available." - ); - } - let self_addr = context - .get_config(Config::ConfiguredAddr) - .ok_or(format_err!("Failed to get self address."))?; + let self_addr = dc_ensure_secret_key_exists(context)?; let private_key = Key::from_self_private(context, self_addr, &context.sql) .ok_or(format_err!("Failed to get private key."))?; let ac_headers = match context @@ -534,7 +529,7 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t) } else { if what == 1 || what == 11 { /* before we export anything, make sure the private key exists */ - if 0 == dc_ensure_secret_key_exists(context) { + if dc_ensure_secret_key_exists(context).is_err() { error!( context, 0, @@ -1284,147 +1279,15 @@ unsafe fn export_key_to_asc_file( mod tests { use super::*; - use std::ffi::CStr; - use num_traits::ToPrimitive; - use crate::config::Config; - use crate::key; use crate::test_utils::*; - unsafe extern "C" fn logging_cb( - _ctx: &Context, - evt: Event, - _d1: uintptr_t, - d2: uintptr_t, - ) -> uintptr_t { - let to_str = |x| CStr::from_ptr(x as *const libc::c_char).to_str().unwrap(); - match evt { - Event::INFO => println!("I: {}", to_str(d2)), - Event::WARNING => println!("W: {}", to_str(d2)), - Event::ERROR => println!("E: {}", to_str(d2)), - _ => (), - } - 0 - } - - /// Create Alice with a pre-generated keypair. - fn create_alice_keypair(ctx: &Context) { - ctx.set_config(Config::ConfiguredAddr, Some("alice@example.org")) - .unwrap(); - - // The keypair was created using: - // let (public, private) = crate::pgp::dc_pgp_create_keypair("alice@example.com") - // .unwrap(); - // println!("{}", public.to_base64(64)); - // println!("{}", private.to_base64(64)); - let public = key::Key::from_base64( - concat!( - "xsBNBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l", - "FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX", - "AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4", - "Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9", - "iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw", - "oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAHNEzxhbGljZUBleGFtcGxl", - "LmNvbT7CwIkEEAEIADMCGQEFAl086fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iai", - "x4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9", - "OHUl3MrXtZ7QmHyOAFvbXE/6n5Eeh+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkK", - "A8e4cJqwDOHsyAnvQXZ7WNje9+BMzcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea", - "6zjGF0/qljTdoxTtsYpv5wXYuhwbYklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6", - "GkquJN814Y+xny4xhZzGOfue6SeP12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUK", - "u5wO9FFbgDySOSlEjByGejSGuBmho0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxD", - "Fc7ATQRdPOnsAQgA5oLxXRLnyugzOmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG", - "9JzDeQql+sYXgUSxOoIayItuXtnFn7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av", - "62n18Venlm0yNKpROPcZ6M/sc4m6uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/R", - "noW+/fhmwIg08dQ5m8hQe3GEOZEeLrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q", - "4zW8vk2ztB8ngwbnqYy8zrN1DCICN1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAm", - "jxLZfVDcoObFH3Cv2GB7BEYxv86KC2Y6T74Q/wARAQABwsB2BBgBCAAgBQJdPOn4", - "AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/dXshJnoW", - "qEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJywJoupwX", - "FNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJuiCQvR9m", - "MjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6RDXIeYJf", - "qrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMlammDliPw", - "sK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKObzPqgJCGw", - "jTglkixw+aSTXw==" - ), - KeyType::Public, - ) - .unwrap(); - let private = key::Key::from_base64( - concat!( - "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", - "zPqgJCGwjTglkixw+aSTXw==" - ), - KeyType::Private, - ) - .unwrap(); - let saved = key::dc_key_save_self_keypair( - &ctx, - &public, - &private, - "alice@example.org", - 1, - &ctx.sql, - ); - assert_eq!(saved, true, "Failed to save Alice's key"); - } - #[test] fn test_render_setup_file() { let t = test_context(Some(logging_cb)); - create_alice_keypair(&t.ctx); // Trick things to think we're configured. + configure_alice_keypair(&t.ctx); let msg = dc_render_setup_file(&t.ctx, "hello").unwrap(); println!("{}", &msg); // Check some substrings, indicating things got substituted. @@ -1456,7 +1319,7 @@ mod tests { #[test] fn test_render_setup_file_newline_replace() { let t = test_context(Some(ac_setup_msg_cb)); - create_alice_keypair(&t.ctx); + configure_alice_keypair(&t.ctx); let msg = dc_render_setup_file(&t.ctx, "pw").unwrap(); println!("{}", &msg); assert!(msg.contains("

hello
there

")); diff --git a/src/dc_securejoin.rs b/src/dc_securejoin.rs index 45d970d96..d41a0c410 100644 --- a/src/dc_securejoin.rs +++ b/src/dc_securejoin.rs @@ -42,7 +42,7 @@ pub unsafe fn dc_get_securejoin_qr( let mut group_name_urlencoded = 0 as *mut libc::c_char; let mut qr: Option = None; - dc_ensure_secret_key_exists(context); + dc_ensure_secret_key_exists(context).ok(); invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id); if invitenumber.is_null() { invitenumber = dc_create_id().strdup(); @@ -149,7 +149,7 @@ pub unsafe fn dc_join_securejoin(context: &Context, qr: *const libc::c_char) -> let mut join_vg: libc::c_int = 0i32; let mut qr_scan: *mut dc_lot_t = 0 as *mut dc_lot_t; info!(context, 0, "Requesting secure-join ...",); - dc_ensure_secret_key_exists(context); + dc_ensure_secret_key_exists(context).ok(); ongoing_allocated = dc_alloc_ongoing(context); if !(ongoing_allocated == 0i32) { qr_scan = dc_check_qr(context, qr); diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 2497900dc..fb30358b9 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -1453,9 +1453,9 @@ pub trait StrExt { /// /// This allocates a new raw C string which must be freed using /// `free`. It takes care of some common pitfalls with using - /// [CString::as_ptr]. + /// [CString.as_ptr]. /// - /// [CString::as_ptr]: std::ffi::CString::as_ptr + /// [CString.as_ptr]: std::ffi::CString.as_ptr /// /// # Panics /// diff --git a/src/test_utils.rs b/src/test_utils.rs index 5ba5c0a37..1749b81ba 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -2,9 +2,15 @@ //! //! This module is only compiled for test runs. +use std::ffi::CStr; + +use libc::uintptr_t; use tempfile::{tempdir, TempDir}; +use crate::config::Config; +use crate::constants::{Event, KeyType}; use crate::context::{dc_context_new, dc_open, Context}; +use crate::key; use crate::types::dc_callback_t; /// A Context and temporary directory. @@ -44,3 +50,127 @@ pub fn test_context(cb: Option) -> TestContext { pub fn dummy_context() -> TestContext { test_context(None) } + +pub unsafe extern "C" fn logging_cb( + _ctx: &Context, + evt: Event, + _d1: uintptr_t, + d2: uintptr_t, +) -> uintptr_t { + let to_str = |x| CStr::from_ptr(x as *const libc::c_char).to_str().unwrap(); + match evt { + Event::INFO => println!("I: {}", to_str(d2)), + Event::WARNING => println!("W: {}", to_str(d2)), + Event::ERROR => println!("E: {}", to_str(d2)), + _ => (), + } + 0 +} + +/// Creates Alice with a pre-generated keypair. +/// +/// Returns the address of the keypair created (alice@example.org). +pub fn configure_alice_keypair(ctx: &Context) -> String { + let addr = String::from("alice@example.org"); + ctx.set_config(Config::ConfiguredAddr, Some(&addr)).unwrap(); + + // The keypair was created using: + // let (public, private) = crate::pgp::dc_pgp_create_keypair("alice@example.com") + // .unwrap(); + // println!("{}", public.to_base64(64)); + // println!("{}", private.to_base64(64)); + let public = key::Key::from_base64( + concat!( + "xsBNBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l", + "FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX", + "AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4", + "Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9", + "iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw", + "oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAHNEzxhbGljZUBleGFtcGxl", + "LmNvbT7CwIkEEAEIADMCGQEFAl086fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iai", + "x4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9", + "OHUl3MrXtZ7QmHyOAFvbXE/6n5Eeh+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkK", + "A8e4cJqwDOHsyAnvQXZ7WNje9+BMzcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea", + "6zjGF0/qljTdoxTtsYpv5wXYuhwbYklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6", + "GkquJN814Y+xny4xhZzGOfue6SeP12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUK", + "u5wO9FFbgDySOSlEjByGejSGuBmho0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxD", + "Fc7ATQRdPOnsAQgA5oLxXRLnyugzOmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG", + "9JzDeQql+sYXgUSxOoIayItuXtnFn7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av", + "62n18Venlm0yNKpROPcZ6M/sc4m6uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/R", + "noW+/fhmwIg08dQ5m8hQe3GEOZEeLrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q", + "4zW8vk2ztB8ngwbnqYy8zrN1DCICN1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAm", + "jxLZfVDcoObFH3Cv2GB7BEYxv86KC2Y6T74Q/wARAQABwsB2BBgBCAAgBQJdPOn4", + "AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/dXshJnoW", + "qEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJywJoupwX", + "FNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJuiCQvR9m", + "MjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6RDXIeYJf", + "qrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMlammDliPw", + "sK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKObzPqgJCGw", + "jTglkixw+aSTXw==" + ), + KeyType::Public, + ) + .unwrap(); + let private = key::Key::from_base64( + concat!( + "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", + "zPqgJCGwjTglkixw+aSTXw==" + ), + KeyType::Private, + ) + .unwrap(); + let saved = key::dc_key_save_self_keypair(&ctx, &public, &private, &addr, 1, &ctx.sql); + assert_eq!(saved, true, "Failed to save Alice's key"); + addr +}