mirror of
https://github.com/chatmail/core.git
synced 2026-04-27 18:36:30 +03:00
finish dc_imex refactoring, fix linting, rustify some things
This commit is contained in:
255
src/dc_imex.rs
255
src/dc_imex.rs
@@ -2,7 +2,7 @@ use std::ffi::CString;
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
|
||||
use libc::{free, strcmp, strlen, strstr};
|
||||
use libc::{free, strlen};
|
||||
use mmime::mailmime_content::*;
|
||||
use mmime::mmapstring::*;
|
||||
use mmime::other::*;
|
||||
@@ -30,20 +30,12 @@ use crate::stock::StockMessage;
|
||||
// param1 is a directory where the keys are searched in and read from
|
||||
// param1 is a directory where the backup is written to
|
||||
// param1 is the file with the backup to import
|
||||
pub fn dc_imex(
|
||||
context: &Context,
|
||||
what: libc::c_int,
|
||||
param1: Option<impl AsRef<Path>>,
|
||||
param2: Option<impl AsRef<Path>>,
|
||||
) {
|
||||
pub fn dc_imex(context: &Context, what: libc::c_int, param1: Option<impl AsRef<Path>>) {
|
||||
let mut param = Params::new();
|
||||
param.set_int(Param::Cmd, what as i32);
|
||||
if let Some(param1) = param1 {
|
||||
param.set(Param::Arg, param1.as_ref().to_string_lossy());
|
||||
}
|
||||
if let Some(param2) = param2 {
|
||||
param.set(Param::Arg, param2.as_ref().to_string_lossy());
|
||||
}
|
||||
|
||||
job_kill_action(context, Action::ImexImap);
|
||||
job_add(context, Action::ImexImap, 0, param, 0);
|
||||
@@ -268,7 +260,20 @@ pub unsafe fn dc_continue_key_transfer(context: &Context, msg_id: u32, setup_cod
|
||||
free(armored_key as *mut libc::c_void);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
armored_key = dc_decrypt_setup_file(context, norm_sc, buf.as_ptr().cast());
|
||||
if armored_key.is_null() {
|
||||
error!(context, "Cannot decrypt Autocrypt Setup Message.",);
|
||||
} else {
|
||||
let armored_key_r = as_str(armored_key);
|
||||
match set_self_key(context, armored_key_r, true, true) {
|
||||
Ok(()) => {
|
||||
success = true;
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(context, "set-self-key failed: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error!(context, "Cannot read Autocrypt Setup Message file.",);
|
||||
@@ -282,55 +287,61 @@ pub unsafe fn dc_continue_key_transfer(context: &Context, msg_id: u32, setup_cod
|
||||
|
||||
fn set_self_key(
|
||||
context: &Context,
|
||||
armored_c: *const libc::c_char,
|
||||
set_default: libc::c_int,
|
||||
) -> bool {
|
||||
assert!(!armored_c.is_null(), "invalid buffer");
|
||||
let armored = as_str(armored_c);
|
||||
|
||||
armored: &str,
|
||||
set_default: bool,
|
||||
prefer_encrypt_required: bool,
|
||||
) -> Result<()> {
|
||||
// try hard to only modify key-state
|
||||
let keys = Key::from_armored_string(armored, KeyType::Private)
|
||||
.and_then(|(k, h)| if k.verify() { Some((k, h)) } else { None })
|
||||
.and_then(|(k, h)| k.split_key().map(|pub_key| (k, pub_key, h)));
|
||||
|
||||
if keys.is_none() {
|
||||
error!(context, "File does not contain a valid private key.",);
|
||||
return false;
|
||||
bail!("File does not contain a valid private key.");
|
||||
}
|
||||
|
||||
let (private_key, public_key, header) = keys.unwrap();
|
||||
let preferencrypt = header.get("Autocrypt-Prefer-Encrypt");
|
||||
match preferencrypt.map(|s| s.as_str()) {
|
||||
Some(headerval) => {
|
||||
let e2ee_enabled = match headerval {
|
||||
"nopreference" => 0,
|
||||
"mutual" => 1,
|
||||
_ => {
|
||||
bail!("invalid Autocrypt-Prefer-Encrypt header: {:?}", header);
|
||||
}
|
||||
};
|
||||
context
|
||||
.sql
|
||||
.set_config_int(context, "e2ee_enabled", e2ee_enabled)?;
|
||||
}
|
||||
None => {
|
||||
if prefer_encrypt_required {
|
||||
bail!("missing Autocrypt-Prefer-Encrypt header");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if sql::execute(
|
||||
let self_addr = context.get_config(Config::ConfiguredAddr);
|
||||
if self_addr.is_none() {
|
||||
bail!("Missing self addr");
|
||||
}
|
||||
|
||||
// XXX maybe better make dc_key_save_self_keypair delete things
|
||||
sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"DELETE FROM keypairs WHERE public_key=? OR private_key=?;",
|
||||
params![public_key.to_bytes(), private_key.to_bytes()],
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
)?;
|
||||
|
||||
if 0 != set_default {
|
||||
if sql::execute(
|
||||
if set_default {
|
||||
sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"UPDATE keypairs SET is_default=0;",
|
||||
params![],
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
error!(context, "File does not contain a private key.",);
|
||||
}
|
||||
|
||||
let self_addr = context.get_config(Config::ConfiguredAddr);
|
||||
|
||||
if self_addr.is_none() {
|
||||
error!(context, "Missing self addr");
|
||||
return false;
|
||||
)?;
|
||||
}
|
||||
|
||||
if !dc_key_save_self_keypair(
|
||||
@@ -338,25 +349,12 @@ fn set_self_key(
|
||||
&public_key,
|
||||
&private_key,
|
||||
self_addr.unwrap(),
|
||||
set_default,
|
||||
set_default as libc::c_int,
|
||||
&context.sql,
|
||||
) {
|
||||
error!(context, "Cannot save keypair.");
|
||||
return false;
|
||||
}
|
||||
|
||||
match preferencrypt.map(|s| s.as_str()) {
|
||||
Some("") => false,
|
||||
Some("nopreference") => context
|
||||
.sql
|
||||
.set_config_int(context, "e2ee_enabled", 0)
|
||||
.is_ok(),
|
||||
Some("mutual") => context
|
||||
.sql
|
||||
.set_config_int(context, "e2ee_enabled", 1)
|
||||
.is_ok(),
|
||||
_ => true,
|
||||
bail!("Cannot save keypair, internal key-state possibly corrupted now!");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub unsafe fn dc_decrypt_setup_file(
|
||||
@@ -365,7 +363,7 @@ pub unsafe fn dc_decrypt_setup_file(
|
||||
filecontent: *const libc::c_char,
|
||||
) -> *mut libc::c_char {
|
||||
let fc_buf: *mut libc::c_char;
|
||||
let mut fc_headerline: *const libc::c_char = ptr::null();
|
||||
let mut fc_headerline = String::default();
|
||||
let mut fc_base64: *const libc::c_char = ptr::null();
|
||||
let mut binary: *mut libc::c_char = ptr::null_mut();
|
||||
let mut binary_bytes: libc::size_t = 0;
|
||||
@@ -379,11 +377,7 @@ pub unsafe fn dc_decrypt_setup_file(
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
&mut fc_base64,
|
||||
) && !fc_headerline.is_null()
|
||||
&& strcmp(
|
||||
fc_headerline,
|
||||
b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0
|
||||
) && fc_headerline == "-----BEGIN PGP MESSAGE-----"
|
||||
&& !fc_base64.is_null()
|
||||
{
|
||||
/* convert base64 to binary */
|
||||
@@ -464,7 +458,7 @@ pub fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) -> Result<()> {
|
||||
}
|
||||
let success = match what {
|
||||
DC_IMEX_EXPORT_SELF_KEYS => export_self_keys(context, ¶m1_s),
|
||||
DC_IMEX_IMPORT_SELF_KEYS => unsafe { import_self_keys(context, ¶m1_s) },
|
||||
DC_IMEX_IMPORT_SELF_KEYS => import_self_keys(context, ¶m1_s),
|
||||
DC_IMEX_EXPORT_BACKUP => unsafe { export_backup(context, param1.as_ptr()) },
|
||||
DC_IMEX_IMPORT_BACKUP => unsafe { import_backup(context, param1.as_ptr()) },
|
||||
_ => {
|
||||
@@ -773,105 +767,88 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> bool {
|
||||
/*******************************************************************************
|
||||
* Classic key import
|
||||
******************************************************************************/
|
||||
unsafe fn import_self_keys(context: &Context, dir_name: &str) -> bool {
|
||||
fn import_self_keys(context: &Context, dir_name: &str) -> bool {
|
||||
/* hint: even if we switch to import Autocrypt Setup Files, we should leave the possibility to import
|
||||
plain ASC keys, at least keys without a password, if we do not want to implement a password entry function.
|
||||
Importing ASC keys is useful to use keys in Delta Chat used by any other non-Autocrypt-PGP implementation.
|
||||
|
||||
Maybe we should make the "default" key handlong also a little bit smarter
|
||||
(currently, the last imported key is the standard key unless it contains the string "legacy" in its name) */
|
||||
let mut set_default: libc::c_int;
|
||||
let mut buf: *mut libc::c_char = ptr::null_mut();
|
||||
// a pointer inside buf, MUST NOT be free()'d
|
||||
let mut private_key: *const libc::c_char;
|
||||
let mut buf2: *mut libc::c_char = ptr::null_mut();
|
||||
// a pointer inside buf2, MUST NOT be free()'d
|
||||
let mut buf2_headerline: *const libc::c_char = ptr::null_mut();
|
||||
if dir_name.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let mut set_default: bool;
|
||||
let mut key: String;
|
||||
let mut imported_cnt = 0;
|
||||
if !dir_name.is_empty() {
|
||||
let dir = std::path::Path::new(dir_name);
|
||||
if let Ok(dir_handle) = std::fs::read_dir(dir) {
|
||||
for entry in dir_handle {
|
||||
if let Err(err) = entry {
|
||||
|
||||
let dir = std::path::Path::new(dir_name);
|
||||
if let Ok(dir_handle) = std::fs::read_dir(dir) {
|
||||
for entry in dir_handle {
|
||||
let entry_fn = match entry {
|
||||
Err(err) => {
|
||||
info!(context, "file-dir error: {}", err);
|
||||
break;
|
||||
}
|
||||
let entry_fn = entry.unwrap().file_name();
|
||||
let name_f = entry_fn.to_string_lossy();
|
||||
|
||||
info!(context, "Checking name_f: {}", name_f);
|
||||
match dc_get_filesuffix_lc(&name_f) {
|
||||
Some(suffix) => {
|
||||
if suffix != "asc" {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
Ok(res) => res.file_name(),
|
||||
};
|
||||
let name_f = entry_fn.to_string_lossy();
|
||||
let path_plus_name = dir.join(&entry_fn);
|
||||
match dc_get_filesuffix_lc(&name_f) {
|
||||
Some(suffix) => {
|
||||
if suffix != "asc" {
|
||||
continue;
|
||||
}
|
||||
set_default = if name_f.contains("legacy") {
|
||||
info!(context, "found legacy key '{}'", path_plus_name.display());
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
let path_plus_name = dir.join(&entry_fn);
|
||||
info!(context, "Checking: {}", path_plus_name.display());
|
||||
|
||||
free(buf.cast());
|
||||
buf = ptr::null_mut();
|
||||
|
||||
if let Ok(buf_r) = dc_read_file(context, &path_plus_name) {
|
||||
buf = buf_r.as_ptr() as *mut _;
|
||||
std::mem::forget(buf_r);
|
||||
} else {
|
||||
None => {
|
||||
continue;
|
||||
};
|
||||
}
|
||||
}
|
||||
if let Ok(content) = dc_read_file(context, &path_plus_name) {
|
||||
key = String::from_utf8_lossy(&content).to_string();
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
private_key = buf;
|
||||
|
||||
free(buf2 as *mut libc::c_void);
|
||||
buf2 = dc_strdup(buf);
|
||||
if dc_split_armored_data(
|
||||
/* only import if we have a private key */
|
||||
let mut buf2_headerline = String::default();
|
||||
let split_res: bool;
|
||||
unsafe {
|
||||
let buf2 = "".strdup();
|
||||
split_res = dc_split_armored_data(
|
||||
buf2,
|
||||
&mut buf2_headerline,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
) && strcmp(
|
||||
buf2_headerline,
|
||||
b"-----BEGIN PGP PUBLIC KEY BLOCK-----\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0
|
||||
{
|
||||
private_key = strstr(
|
||||
buf,
|
||||
b"-----BEGIN PGP PRIVATE KEY BLOCK\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
if private_key.is_null() {
|
||||
/* this is no error but quite normal as we always export the public keys together with the private ones */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
set_default = 1;
|
||||
if name_f.contains("legacy") {
|
||||
info!(
|
||||
context,
|
||||
"Treating \"{}\" as a legacy private key.",
|
||||
path_plus_name.display(),
|
||||
);
|
||||
set_default = 0i32
|
||||
}
|
||||
if !set_self_key(context, private_key, set_default) {
|
||||
continue;
|
||||
}
|
||||
imported_cnt += 1
|
||||
);
|
||||
free(buf2 as *mut libc::c_void);
|
||||
}
|
||||
if imported_cnt == 0i32 {
|
||||
error!(context, "No private keys found in \"{}\".", dir_name,);
|
||||
if split_res
|
||||
&& buf2_headerline.contains("-----BEGIN PGP PUBLIC KEY BLOCK-----")
|
||||
&& !key.contains("-----BEGIN PGP PRIVATE KEY BLOCK")
|
||||
{
|
||||
info!(context, "ignoring public key file '{}", name_f);
|
||||
// it's fine: DC exports public with private
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
error!(context, "Import: Cannot open directory \"{}\".", dir_name,);
|
||||
if let Err(err) = set_self_key(context, &key, set_default, false) {
|
||||
error!(context, "set_self_key: {}", err);
|
||||
continue;
|
||||
}
|
||||
imported_cnt += 1
|
||||
}
|
||||
if imported_cnt == 0i32 {
|
||||
error!(context, "No private keys found in \"{}\".", dir_name,);
|
||||
}
|
||||
} else {
|
||||
error!(context, "Import: Cannot open directory \"{}\".", dir_name,);
|
||||
}
|
||||
|
||||
free(buf as *mut libc::c_void);
|
||||
free(buf2 as *mut libc::c_void);
|
||||
|
||||
imported_cnt != 0
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};
|
||||
use std::ptr;
|
||||
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
use libc::{free, strcmp};
|
||||
use libc::free;
|
||||
|
||||
use crate::chat::{self, Chat};
|
||||
use crate::constants::*;
|
||||
@@ -353,7 +353,7 @@ impl Message {
|
||||
if let Ok(mut buf) = dc_read_file(context, filename) {
|
||||
unsafe {
|
||||
// just a pointer inside buf, MUST NOT be free()'d
|
||||
let mut buf_headerline = ptr::null();
|
||||
let mut buf_headerline = String::default();
|
||||
// just a pointer inside buf, MUST NOT be free()'d
|
||||
let mut buf_setupcodebegin = ptr::null();
|
||||
|
||||
@@ -363,10 +363,7 @@ impl Message {
|
||||
&mut buf_setupcodebegin,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
) && strcmp(
|
||||
buf_headerline,
|
||||
b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0
|
||||
) && buf_headerline == "-----BEGIN PGP MESSAGE-----"
|
||||
&& !buf_setupcodebegin.is_null()
|
||||
{
|
||||
return Some(to_string(buf_setupcodebegin));
|
||||
|
||||
11
src/pgp.rs
11
src/pgp.rs
@@ -19,7 +19,7 @@ use crate::keyring::*;
|
||||
|
||||
pub unsafe fn dc_split_armored_data(
|
||||
buf: *mut libc::c_char,
|
||||
ret_headerline: *mut *const libc::c_char,
|
||||
ret_headerline: *mut String,
|
||||
ret_setupcodebegin: *mut *const libc::c_char,
|
||||
ret_preferencrypt: *mut *const libc::c_char,
|
||||
ret_base64: *mut *const libc::c_char,
|
||||
@@ -31,9 +31,6 @@ pub unsafe fn dc_split_armored_data(
|
||||
let mut p2: *mut libc::c_char;
|
||||
let mut headerline: *mut libc::c_char = ptr::null_mut();
|
||||
let mut base64: *mut libc::c_char = ptr::null_mut();
|
||||
if !ret_headerline.is_null() {
|
||||
*ret_headerline = ptr::null()
|
||||
}
|
||||
if !ret_setupcodebegin.is_null() {
|
||||
*ret_setupcodebegin = ptr::null_mut();
|
||||
}
|
||||
@@ -43,7 +40,7 @@ pub unsafe fn dc_split_armored_data(
|
||||
if !ret_base64.is_null() {
|
||||
*ret_base64 = ptr::null();
|
||||
}
|
||||
if !(buf.is_null() || ret_headerline.is_null()) {
|
||||
if !buf.is_null() {
|
||||
dc_remove_cr_chars(buf);
|
||||
while 0 != *p1 {
|
||||
if *p1 as libc::c_int == '\n' as i32 {
|
||||
@@ -62,9 +59,7 @@ pub unsafe fn dc_split_armored_data(
|
||||
) == 0i32
|
||||
{
|
||||
headerline = line;
|
||||
if !ret_headerline.is_null() {
|
||||
*ret_headerline = headerline
|
||||
}
|
||||
*ret_headerline = as_str(headerline).to_string();
|
||||
}
|
||||
} else if strspn(line, b"\t\r\n \x00" as *const u8 as *const libc::c_char)
|
||||
== strlen(line)
|
||||
|
||||
Reference in New Issue
Block a user