From f31f603c8bdefc86aa496249a984436dd0207b2c Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Sat, 3 Aug 2019 23:39:10 +0200 Subject: [PATCH] Turn dc_ensure_secret_key_existy into something more rusty This marks the function safe and returns Result, it also now returns the ConfiguredAddr since it has to look this up anyway and it makes testing more easy. Turns out it reduces some duplicate SQL query in some callers too. More test code has been moved from dc_imex to test_utils as it's more genrally applicable. --- deltachat-ffi/src/lib.rs | 7 +- examples/repl/cmdline.rs | 2 +- src/contact.rs | 11 ++- src/dc_configure.rs | 2 +- src/dc_e2ee.rs | 62 ++++++++++------ src/dc_imex.rs | 151 ++------------------------------------- src/dc_securejoin.rs | 4 +- src/dc_tools.rs | 4 +- src/test_utils.rs | 130 +++++++++++++++++++++++++++++++++ 9 files changed, 199 insertions(+), 174 deletions(-) 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 +}