mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
refactor: move aheader to safe rust
This commit is contained in:
@@ -509,3 +509,10 @@ pub const DC_STR_MSGLOCATIONENABLED: usize = 64;
|
||||
pub const DC_STR_MSGLOCATIONDISABLED: usize = 65;
|
||||
pub const DC_STR_LOCATION: usize = 66;
|
||||
pub const DC_STR_COUNT: usize = 66;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum Key {
|
||||
Public = 0,
|
||||
Private = 1,
|
||||
}
|
||||
|
||||
@@ -1,283 +1,318 @@
|
||||
use mmime::mailimf_types::*;
|
||||
use std::collections::BTreeMap;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::str::FromStr;
|
||||
use std::{fmt, str};
|
||||
|
||||
use mmime::mailimf_types::*;
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::dc_contact::*;
|
||||
use crate::dc_key::*;
|
||||
use crate::dc_strbuilder::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
/// Possible values for encryption preference
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy, FromPrimitive, ToPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum EncryptPreference {
|
||||
NoPreference = 0,
|
||||
Mutual = 1,
|
||||
Reset = 20,
|
||||
}
|
||||
|
||||
impl Default for EncryptPreference {
|
||||
fn default() -> Self {
|
||||
EncryptPreference::NoPreference
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for EncryptPreference {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
EncryptPreference::Mutual => write!(fmt, "mutual"),
|
||||
EncryptPreference::NoPreference => write!(fmt, "nopreference"),
|
||||
EncryptPreference::Reset => write!(fmt, "reset"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl str::FromStr for EncryptPreference {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"mutual" => Ok(EncryptPreference::Mutual),
|
||||
"reset" => Ok(EncryptPreference::Reset),
|
||||
_ => Ok(EncryptPreference::NoPreference),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse and create [Autocrypt-headers](https://autocrypt.org/en/latest/level1.html#the-autocrypt-header).
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct dc_aheader_t {
|
||||
pub addr: *mut libc::c_char,
|
||||
pub struct Aheader {
|
||||
pub addr: String,
|
||||
pub public_key: *mut dc_key_t,
|
||||
pub prefer_encrypt: libc::c_int,
|
||||
pub prefer_encrypt: EncryptPreference,
|
||||
}
|
||||
|
||||
/// the returned pointer is ref'd and must be unref'd after usage
|
||||
pub unsafe fn dc_aheader_new() -> *mut dc_aheader_t {
|
||||
let mut aheader = calloc(1, ::std::mem::size_of::<dc_aheader_t>()) as *mut dc_aheader_t;
|
||||
|
||||
if aheader.is_null() {
|
||||
// TODO replace with enum (hardcoded in deltachat-core) /rtn
|
||||
exit(37);
|
||||
impl Aheader {
|
||||
pub fn new(addr: String, public_key: *mut dc_key_t, prefer_encrypt: EncryptPreference) -> Self {
|
||||
Aheader {
|
||||
addr,
|
||||
public_key,
|
||||
prefer_encrypt,
|
||||
}
|
||||
}
|
||||
|
||||
(*aheader).public_key = dc_key_new();
|
||||
pub fn from_imffields(
|
||||
wanted_from: *const libc::c_char,
|
||||
header: *const mailimf_fields,
|
||||
) -> Option<Self> {
|
||||
if wanted_from.is_null() || header.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
aheader
|
||||
}
|
||||
let mut fine_header = None;
|
||||
let mut cur = unsafe { (*(*header).fld_list).first };
|
||||
|
||||
pub unsafe fn dc_aheader_new_from_imffields(
|
||||
wanted_from: *const libc::c_char,
|
||||
header: *const mailimf_fields,
|
||||
) -> *mut dc_aheader_t {
|
||||
let mut cur;
|
||||
let mut fine_header = 0 as *mut dc_aheader_t;
|
||||
|
||||
if wanted_from.is_null() || header.is_null() {
|
||||
return 0 as *mut dc_aheader_t;
|
||||
}
|
||||
|
||||
cur = (*(*header).fld_list).first;
|
||||
while !cur.is_null() {
|
||||
let field = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailimf_field;
|
||||
|
||||
if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
|
||||
let optional_field = (*field).fld_data.fld_optional_field;
|
||||
if !optional_field.is_null()
|
||||
&& !(*optional_field).fld_name.is_null()
|
||||
&& strcasecmp(
|
||||
(*optional_field).fld_name,
|
||||
b"Autocrypt\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0
|
||||
while !cur.is_null() {
|
||||
let field = unsafe { (*cur).data as *mut mailimf_field };
|
||||
if !field.is_null()
|
||||
&& unsafe { (*field).fld_type } == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int
|
||||
{
|
||||
let mut test = dc_aheader_new();
|
||||
if 0 == dc_aheader_set_from_string(test, (*optional_field).fld_value)
|
||||
|| dc_addr_cmp((*test).addr, wanted_from) != 0
|
||||
let optional_field = unsafe { (*field).fld_data.fld_optional_field };
|
||||
if !optional_field.is_null()
|
||||
&& unsafe { !(*optional_field).fld_name.is_null() }
|
||||
&& unsafe { CStr::from_ptr((*optional_field).fld_name).to_str().unwrap() }
|
||||
== "Autocrypt"
|
||||
{
|
||||
dc_aheader_unref(test);
|
||||
test = 0 as *mut dc_aheader_t
|
||||
}
|
||||
if fine_header.is_null() {
|
||||
fine_header = test
|
||||
} else if !test.is_null() {
|
||||
dc_aheader_unref(fine_header);
|
||||
dc_aheader_unref(test);
|
||||
return 0 as *mut dc_aheader_t;
|
||||
let value = unsafe {
|
||||
CStr::from_ptr((*optional_field).fld_value)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
match Self::from_str(value) {
|
||||
Ok(test) => {
|
||||
// TODO: implement rust-safe version of dc_addr_cmp
|
||||
let addr = CString::new(test.addr.clone()).unwrap();
|
||||
if unsafe { dc_addr_cmp(addr.as_ptr(), wanted_from) } == 0 {
|
||||
if fine_header.is_none() {
|
||||
fine_header = Some(test);
|
||||
} else {
|
||||
// TODO: figure out what kind of error case this is
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cur = unsafe { (*cur).next };
|
||||
}
|
||||
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
|
||||
fine_header
|
||||
}
|
||||
|
||||
pub unsafe fn dc_aheader_unref(aheader: *mut dc_aheader_t) {
|
||||
if aheader.is_null() {
|
||||
return;
|
||||
}
|
||||
free((*aheader).addr as *mut libc::c_void);
|
||||
dc_key_unref((*aheader).public_key);
|
||||
free(aheader as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_aheader_set_from_string(
|
||||
mut aheader: *mut dc_aheader_t,
|
||||
header_str__: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let current_block: u64;
|
||||
/* according to RFC 5322 (Internet Message Format), the given string may contain `\r\n` before any whitespace.
|
||||
we can ignore this issue as
|
||||
(a) no key or value is expected to contain spaces,
|
||||
(b) for the key, non-base64-characters are ignored and
|
||||
(c) for parsing, we ignore `\r\n` as well as tabs for spaces */
|
||||
let mut header_str = 0 as *mut libc::c_char;
|
||||
let mut p;
|
||||
let mut beg_attr_name;
|
||||
let mut after_attr_name;
|
||||
let mut beg_attr_value;
|
||||
let mut success: libc::c_int = 0;
|
||||
|
||||
dc_aheader_empty(aheader);
|
||||
if !(aheader.is_null() || header_str__.is_null()) {
|
||||
(*aheader).prefer_encrypt = 0;
|
||||
header_str = dc_strdup(header_str__);
|
||||
p = header_str;
|
||||
loop {
|
||||
if !(0 != *p) {
|
||||
current_block = 5689316957504528238;
|
||||
break;
|
||||
}
|
||||
p = p.offset(strspn(p, b"\t\r\n =;\x00" as *const u8 as *const libc::c_char) as isize);
|
||||
beg_attr_name = p;
|
||||
beg_attr_value = 0 as *mut libc::c_char;
|
||||
p = p.offset(strcspn(p, b"\t\r\n =;\x00" as *const u8 as *const libc::c_char) as isize);
|
||||
if !(p != beg_attr_name) {
|
||||
continue;
|
||||
}
|
||||
after_attr_name = p;
|
||||
p = p.offset(strspn(p, b"\t\r\n \x00" as *const u8 as *const libc::c_char) as isize);
|
||||
if *p as libc::c_int == '=' as i32 {
|
||||
p = p.offset(
|
||||
strspn(p, b"\t\r\n =\x00" as *const u8 as *const libc::c_char) as isize,
|
||||
);
|
||||
beg_attr_value = p;
|
||||
p = p.offset(strcspn(p, b";\x00" as *const u8 as *const libc::c_char) as isize);
|
||||
if *p as libc::c_int != '\u{0}' as i32 {
|
||||
*p = '\u{0}' as i32 as libc::c_char;
|
||||
p = p.offset(1isize)
|
||||
}
|
||||
dc_trim(beg_attr_value);
|
||||
} else {
|
||||
p = p
|
||||
.offset(strspn(p, b"\t\r\n ;\x00" as *const u8 as *const libc::c_char) as isize)
|
||||
}
|
||||
*after_attr_name = '\u{0}' as i32 as libc::c_char;
|
||||
if !(0 == add_attribute(aheader, beg_attr_name, beg_attr_value)) {
|
||||
continue;
|
||||
}
|
||||
/* a bad attribute makes the whole header invalid */
|
||||
current_block = 9271062167157603455;
|
||||
break;
|
||||
}
|
||||
match current_block {
|
||||
9271062167157603455 => {}
|
||||
_ => {
|
||||
if !(*aheader).addr.is_null() && !(*(*aheader).public_key).binary.is_null() {
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(header_str as *mut libc::c_void);
|
||||
if 0 == success {
|
||||
dc_aheader_empty(aheader);
|
||||
}
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
pub unsafe fn dc_aheader_empty(mut aheader: *mut dc_aheader_t) {
|
||||
if aheader.is_null() {
|
||||
return;
|
||||
}
|
||||
(*aheader).prefer_encrypt = 0;
|
||||
free((*aheader).addr as *mut libc::c_void);
|
||||
(*aheader).addr = 0 as *mut libc::c_char;
|
||||
|
||||
if !(*(*aheader).public_key).binary.is_null() {
|
||||
dc_key_unref((*aheader).public_key);
|
||||
(*aheader).public_key = dc_key_new()
|
||||
fine_header
|
||||
}
|
||||
}
|
||||
|
||||
/* ******************************************************************************
|
||||
* Parse Autocrypt Header
|
||||
******************************************************************************/
|
||||
|
||||
unsafe fn add_attribute(
|
||||
mut aheader: *mut dc_aheader_t,
|
||||
name: *const libc::c_char,
|
||||
value: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
if strcasecmp(name, b"addr\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
if value.is_null() || !dc_may_be_valid_addr(value) || !(*aheader).addr.is_null() {
|
||||
return 0;
|
||||
}
|
||||
(*aheader).addr = dc_addr_normalize(value);
|
||||
return 1;
|
||||
} else {
|
||||
if strcasecmp(
|
||||
name,
|
||||
b"prefer-encrypt\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0
|
||||
{
|
||||
if !value.is_null()
|
||||
&& strcasecmp(value, b"mutual\x00" as *const u8 as *const libc::c_char) == 0
|
||||
{
|
||||
(*aheader).prefer_encrypt = 1;
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
if strcasecmp(name, b"keydata\x00" as *const u8 as *const libc::c_char) == 0 {
|
||||
if value.is_null()
|
||||
|| !(*(*aheader).public_key).binary.is_null()
|
||||
|| 0 != (*(*aheader).public_key).bytes
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return dc_key_set_from_base64((*aheader).public_key, value, 0);
|
||||
} else {
|
||||
if *name.offset(0isize) as libc::c_int == '_' as i32 {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
pub unsafe fn dc_aheader_render(aheader: *const dc_aheader_t) -> *mut libc::c_char {
|
||||
let mut success: bool = false;
|
||||
let mut keybase64_wrapped: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut ret: dc_strbuilder_t = dc_strbuilder_t {
|
||||
buf: 0 as *mut libc::c_char,
|
||||
allocated: 0,
|
||||
free: 0,
|
||||
eos: 0 as *mut libc::c_char,
|
||||
};
|
||||
dc_strbuilder_init(&mut ret, 0);
|
||||
if !(aheader.is_null()
|
||||
|| (*aheader).addr.is_null()
|
||||
|| (*(*aheader).public_key).binary.is_null()
|
||||
|| (*(*aheader).public_key).type_0 != 0)
|
||||
{
|
||||
dc_strbuilder_cat(&mut ret, b"addr=\x00" as *const u8 as *const libc::c_char);
|
||||
dc_strbuilder_cat(&mut ret, (*aheader).addr);
|
||||
dc_strbuilder_cat(&mut ret, b"; \x00" as *const u8 as *const libc::c_char);
|
||||
if (*aheader).prefer_encrypt == 1 {
|
||||
dc_strbuilder_cat(
|
||||
&mut ret,
|
||||
b"prefer-encrypt=mutual; \x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
dc_strbuilder_cat(
|
||||
&mut ret,
|
||||
b"keydata= \x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
impl fmt::Display for Aheader {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
// TODO replace 78 with enum /rtn
|
||||
/* adds a whitespace every 78 characters, this allows libEtPan to wrap the lines according to RFC 5322
|
||||
(which may insert a linebreak before every whitespace) */
|
||||
keybase64_wrapped = dc_key_render_base64((*aheader).public_key, 78);
|
||||
|
||||
if !keybase64_wrapped.is_null() {
|
||||
/*no checksum*/
|
||||
dc_strbuilder_cat(&mut ret, keybase64_wrapped);
|
||||
success = true;
|
||||
}
|
||||
// adds a whitespace every 78 characters, this allows libEtPan to
|
||||
// wrap the lines according to RFC 5322
|
||||
// (which may insert a linebreak before every whitespace)
|
||||
let keydata = dc_key_render_base64_string(self.public_key, 78);
|
||||
write!(
|
||||
fmt,
|
||||
"addr={}; prefer-encrypt={}; keydata={}",
|
||||
self.addr, self.prefer_encrypt, keydata
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl str::FromStr for Aheader {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut attributes: BTreeMap<String, String> = s
|
||||
.split(";")
|
||||
.filter_map(|a| {
|
||||
let attribute: Vec<&str> = a.trim().splitn(2, "=").collect();
|
||||
if attribute.len() < 2 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((
|
||||
attribute[0].trim().to_string(),
|
||||
attribute[1].trim().to_string(),
|
||||
))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let addr = match attributes.remove("addr") {
|
||||
Some(addr) => addr,
|
||||
None => {
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
let public_key = match attributes.remove("keydata") {
|
||||
Some(raw) => {
|
||||
let key = unsafe { dc_key_new() };
|
||||
unsafe {
|
||||
dc_key_set_from_base64(
|
||||
key,
|
||||
CString::new(raw).unwrap().as_ptr(),
|
||||
Key::Public.to_i32().unwrap(),
|
||||
)
|
||||
};
|
||||
key
|
||||
}
|
||||
None => {
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
let prefer_encrypt = match attributes
|
||||
.remove("prefer-encrypt")
|
||||
.and_then(|raw| raw.parse().ok())
|
||||
{
|
||||
Some(pref) => pref,
|
||||
None => EncryptPreference::NoPreference,
|
||||
};
|
||||
|
||||
// Autocrypt-Level0: unknown attributes starting with an underscore can be safely ignored
|
||||
// Autocrypt-Level0: unknown attribute, treat the header as invalid
|
||||
if attributes.keys().find(|k| !k.starts_with("_")).is_some() {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
Ok(Aheader {
|
||||
addr,
|
||||
public_key,
|
||||
prefer_encrypt,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Aheader {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
dc_key_unref(self.public_key);
|
||||
}
|
||||
self.public_key = std::ptr::null_mut();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::pgp as rpgp;
|
||||
|
||||
fn rawkey() -> String {
|
||||
"mDMEWFUX7RYJKwYBBAHaRw8BAQdACHq6FkRGsHqBMsNpD7d+aQ2jtxVwTO+Y4NhBaQyHaMj+0HWFsaWNlQHRlc3RzdWl0ZS5hdXRvY3J5cHQub3JniJAEExYIADgWIQQmqmdR/XZoxC+kkkr8dE2p/nPD1AUCWFUX7QIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRD8dE2p/nPD1EqOAP0WUDKwko001X7XTSYbWGWmXfR9P1Aw6917EnkVQMsp3gEA86Ii8ArL3jd+E2qS5JSysx/qiVhuTSwWzmC5K6zKdg+4OARYVRfuEgorBgEEAZdVAQUBAQdAv1A88FoCfwz0zSh6NNnUuKuz1p3ctJ3kXMGotsVYjA0DAQgHiHgEGBYIACAWIQQmqmdR/XZoxC+kkkr8dE2p/nPD1AUCWFUX7gIbDAAKCRD8dE2p/nPD1FTOAP4nS14sX7a/nBXBKWAh/oX8iVtkhmZqjy9tG21BcNqb+wEAq73H4+1ncnkscR3Nu4GYzNRSD3NXq68tEESK28kYvw4=".into()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
let h: Aheader = format!(
|
||||
"addr=me@mail.com; prefer-encrypt=mutual; keydata={}",
|
||||
rawkey()
|
||||
)
|
||||
.parse()
|
||||
.expect("failed to parse");
|
||||
|
||||
assert_eq!(h.addr, "me@mail.com");
|
||||
assert_eq!(h.prefer_encrypt, EncryptPreference::Mutual);
|
||||
assert!(!h.public_key.is_null());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str_non_critical() {
|
||||
let raw = format!("addr=me@mail.com; _foo=one; _bar=two; keydata={}", rawkey());
|
||||
let h: Aheader = raw.parse().expect("failed to parse");
|
||||
|
||||
assert_eq!(h.addr, "me@mail.com");
|
||||
assert_eq!(h.prefer_encrypt, EncryptPreference::NoPreference);
|
||||
assert!(!h.public_key.is_null());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str_superflous_critical() {
|
||||
let raw = format!(
|
||||
"addr=me@mail.com; _foo=one; _bar=two; other=me; keydata={}",
|
||||
rawkey()
|
||||
);
|
||||
assert!(raw.parse::<Aheader>().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_good_headers() {
|
||||
let fixed_header = "addr=a@b.example.org; prefer-encrypt=mutual; keydata=xsBNBFzG3j0BCAC6iNhT8zydvCXi8LI/gFnkadMbfmSE/rTJskRRra/utGbLyDta/yTrJgWL7O3y/g 4HdDW/dN2z26Y6W13IMzx9gLInn1KQZChtqWAcr/ReUucXcymwcfg1mdkBGk3TSLeLihN6CJx8Wsv8 ig+kgAzte4f5rqEEAJVQ9WZHuti7UiYs6oRzqTo06CRe9owVXxzdMf0VDQtf7ZFm9dpzKKbhH7Lu88 80iiotQ9/yRCkDGp9fNThsrLdZiK6OIAcIBAqi2rI89aS1dAmnRbktQieCx5izzyYkR1KvVL3gTTll HOzfKVEC2asmtWu2e4se/+O4WMIS1eGrn7GeWVb0Vwc5ABEBAAHNETxhQEBiLmV4YW1wbGUuZGU+ws CJBBABCAAzAhkBBQJcxt5FAhsDBAsJCAcGFQgJCgsCAxYCARYhBI4xxYKBgH3ANh5cufaKrc9mtiML AAoJEPaKrc9mtiML938H/18F+3Wf9/JaAy/8hCO1v4S2PVBhxaKCokaNFtkfaMRne2l087LscCFPiF Nyb4mv6Z3YeK8Xpxlp2sI0ecvdiqLUOGfnxS6tQrj+83EjtIrZ/hXOk1h121QFWH9Zg2VNHtODXjAg dLDC0NWUrclR0ZOqEDQHeo0ibTILdokVfXFN25wakPmGaYJP2y729cb1ve7RzvIvwn+Dddfxo3ao72 rBfLi7l4NQ4S0KsY4cw+/6l5bRCKYCP77wZtvCwUvfVVosLdT43agtSiBI49+ayqvZ8OCvSJa61i+v 81brTiEy9GBod4eAp45Ibsuemkw+gon4ZOvUXHTjwFB+h63MrozOwE0EXMbePQEIAL/vauf1zK8JgC u3V+G+SOX0iWw5xUlCPX+ERpBbWfwu3uAqn4wYXD3JDE/fVAF668xiV4eTPtlSUd5h0mn+G7uXMMOt kb+20SoEt50f8zw8TrL9t+ZsV11GKZWJpCar5AhXWsn6EEi8I2hLL5vn55ZZmHuGgN4jjmkRl3ToKC LhaXwTBjCJem7N5EH7F75wErEITa55v4Lb4Nfca7vnvtYrI1OA446xa8gHra0SINelTD09/JM/Fw4s WVPBaRZmJK/Tnu79N23No9XBUubmFPv1pNexZsQclicnTpt/BEWhiun7d6lfGB63K1aoHRTR1pcrWv BuALuuz0gqar2zlI0AEQEAAcLAdgQYAQgAIAUCXMbeRQIbDBYhBI4xxYKBgH3ANh5cufaKrc9mtiML AAoJEPaKrc9mtiMLKSEIAIyLCRO2OyZ0IYRvRPpMn4p7E+7Pfcz/0mSkOy+1hshgJnqivXurm8zwGr wdMqeV4eslKR9H1RUdWGUQJNbtwmmjrt5DHpIhYHl5t3FpCBaGbV20Omo00Q38lBl9MtrmZkZw+ktE k6X+0xCKssMF+2MADkSOIufbR5HrDVB89VZOHCO9DeXvCUUAw2hyJiL/LHmLzJ40zYoTmb+F//f0k0 j+tRdbkefyRoCmwG7YGiT+2hnCdgcezswnzah5J3ZKlrg7jOGo1LxtbvNUzxNBbC6S/aNgwm6qxo7x egRhmEl5uZ16zwyj4qz+xkjGy25Of5mWfUDoNw7OT7sjUbHOOMc=";
|
||||
|
||||
let ah = Aheader::from_str(fixed_header).expect("failed to parse");
|
||||
assert_eq!(ah.addr, "a@b.example.org");
|
||||
// assert_eq!(unsafe { (*ah.public_key).bytes }, 1212);
|
||||
assert!(valid_key(ah.public_key as *const _));
|
||||
assert_eq!(ah.prefer_encrypt, EncryptPreference::Mutual);
|
||||
|
||||
let rendered = ah.to_string();
|
||||
assert_eq!(rendered, fixed_header);
|
||||
|
||||
let ah = Aheader::from_str(" _foo; __FOO=BAR ;;; addr = a@b.example.org ;\r\n prefer-encrypt = mutual ; keydata = RG VsdGEgQ\r\n2hhdA==").expect("failed to parse");
|
||||
assert_eq!(ah.addr, "a@b.example.org");
|
||||
assert_eq!(unsafe { (*ah.public_key).bytes }, 10);
|
||||
assert_eq!(ah.prefer_encrypt, EncryptPreference::Mutual);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
CStr::from_ptr((*ah.public_key).binary as *const _)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
},
|
||||
"Delta Chat"
|
||||
);
|
||||
|
||||
Aheader::from_str(
|
||||
"addr=a@b.example.org; prefer-encrypt=ignoreUnknownValues; keydata=RGVsdGEgQ2hhdA==",
|
||||
)
|
||||
.expect("failed to parse");
|
||||
|
||||
Aheader::from_str("addr=a@b.example.org; keydata=RGVsdGEgQ2hhdA==")
|
||||
.expect("failed to parse");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_headers() {
|
||||
assert!(Aheader::from_str("").is_err());
|
||||
assert!(Aheader::from_str("foo").is_err());
|
||||
assert!(Aheader::from_str("\n\n\n").is_err());
|
||||
assert!(Aheader::from_str(" ;;").is_err());
|
||||
assert!(Aheader::from_str("addr=a@t.de; unknwon=1; keydata=jau").is_err());
|
||||
}
|
||||
|
||||
fn valid_key(raw_key: *const dc_key_t) -> bool {
|
||||
let mut key_is_valid = false;
|
||||
unsafe {
|
||||
if !(raw_key.is_null() || (*raw_key).binary.is_null() || (*raw_key).bytes <= 0i32) {
|
||||
let key = rpgp::rpgp_key_from_bytes(
|
||||
(*raw_key).binary as *const _,
|
||||
(*raw_key).bytes as usize,
|
||||
);
|
||||
|
||||
if (*raw_key).type_0 == 0i32 && 0 != rpgp::rpgp_key_is_public(key) as libc::c_int {
|
||||
key_is_valid = true;
|
||||
} else if (*raw_key).type_0 == 1i32
|
||||
&& 0 != rpgp::rpgp_key_is_secret(key) as libc::c_int
|
||||
{
|
||||
key_is_valid = true;
|
||||
}
|
||||
if !key.is_null() {
|
||||
rpgp::rpgp_key_drop(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
key_is_valid
|
||||
}
|
||||
|
||||
if !success {
|
||||
free(ret.buf as *mut libc::c_void);
|
||||
ret.buf = 0 as *mut libc::c_char
|
||||
}
|
||||
|
||||
free(keybase64_wrapped as *mut libc::c_void);
|
||||
|
||||
ret.buf
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
use crate::dc_aheader::*;
|
||||
use crate::dc_chat::*;
|
||||
use crate::dc_context::dc_context_t;
|
||||
@@ -81,20 +85,20 @@ unsafe fn dc_apeerstate_empty(mut peerstate: *mut dc_apeerstate_t) {
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_init_from_header(
|
||||
mut peerstate: *mut dc_apeerstate_t,
|
||||
header: *const dc_aheader_t,
|
||||
header: &Aheader,
|
||||
message_time: time_t,
|
||||
) -> libc::c_int {
|
||||
if peerstate.is_null() || header.is_null() {
|
||||
if peerstate.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
dc_apeerstate_empty(peerstate);
|
||||
(*peerstate).addr = dc_strdup((*header).addr);
|
||||
(*peerstate).addr = dc_strdup(CString::new(header.addr.clone()).unwrap().as_ptr());
|
||||
(*peerstate).last_seen = message_time;
|
||||
(*peerstate).last_seen_autocrypt = message_time;
|
||||
(*peerstate).to_save |= 0x2i32;
|
||||
(*peerstate).prefer_encrypt = (*header).prefer_encrypt;
|
||||
(*peerstate).prefer_encrypt = header.prefer_encrypt.to_i32().unwrap();
|
||||
(*peerstate).public_key = dc_key_new();
|
||||
dc_key_set_from_key((*peerstate).public_key, (*header).public_key);
|
||||
dc_key_set_from_key((*peerstate).public_key, header.public_key);
|
||||
dc_apeerstate_recalc_fingerprint(peerstate);
|
||||
|
||||
1
|
||||
@@ -152,20 +156,20 @@ pub unsafe fn dc_apeerstate_recalc_fingerprint(mut peerstate: *mut dc_apeerstate
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe extern "C" fn dc_apeerstate_init_from_gossip(
|
||||
pub unsafe fn dc_apeerstate_init_from_gossip(
|
||||
mut peerstate: *mut dc_apeerstate_t,
|
||||
gossip_header: *const dc_aheader_t,
|
||||
gossip_header: &Aheader,
|
||||
message_time: time_t,
|
||||
) -> libc::c_int {
|
||||
if peerstate.is_null() || gossip_header.is_null() {
|
||||
if peerstate.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
dc_apeerstate_empty(peerstate);
|
||||
(*peerstate).addr = dc_strdup((*gossip_header).addr);
|
||||
(*peerstate).addr = dc_strdup(CString::new(gossip_header.addr.clone()).unwrap().as_ptr());
|
||||
(*peerstate).gossip_timestamp = message_time;
|
||||
(*peerstate).to_save |= 0x2i32;
|
||||
(*peerstate).gossip_key = dc_key_new();
|
||||
dc_key_set_from_key((*peerstate).gossip_key, (*gossip_header).public_key);
|
||||
dc_key_set_from_key((*peerstate).gossip_key, gossip_header.public_key);
|
||||
dc_apeerstate_recalc_fingerprint(peerstate);
|
||||
|
||||
1
|
||||
@@ -191,15 +195,17 @@ pub unsafe fn dc_apeerstate_degrade_encryption(
|
||||
|
||||
pub unsafe fn dc_apeerstate_apply_header(
|
||||
mut peerstate: *mut dc_apeerstate_t,
|
||||
header: *const dc_aheader_t,
|
||||
header: &Aheader,
|
||||
message_time: time_t,
|
||||
) {
|
||||
if peerstate.is_null()
|
||||
|| header.is_null()
|
||||
|| (*peerstate).addr.is_null()
|
||||
|| (*header).addr.is_null()
|
||||
|| (*(*header).public_key).binary.is_null()
|
||||
|| strcasecmp((*peerstate).addr, (*header).addr) != 0i32
|
||||
|| (*header.public_key).binary.is_null()
|
||||
|| CStr::from_ptr((*peerstate).addr)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_lowercase()
|
||||
!= header.addr.to_lowercase()
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -207,13 +213,16 @@ pub unsafe fn dc_apeerstate_apply_header(
|
||||
(*peerstate).last_seen = message_time;
|
||||
(*peerstate).last_seen_autocrypt = message_time;
|
||||
(*peerstate).to_save |= 0x1i32;
|
||||
if ((*header).prefer_encrypt == 1i32 || (*header).prefer_encrypt == 0i32)
|
||||
&& (*header).prefer_encrypt != (*peerstate).prefer_encrypt
|
||||
if (header.prefer_encrypt == EncryptPreference::Mutual
|
||||
|| header.prefer_encrypt == EncryptPreference::NoPreference)
|
||||
&& header.prefer_encrypt.to_i32().unwrap() != (*peerstate).prefer_encrypt
|
||||
{
|
||||
if (*peerstate).prefer_encrypt == 1i32 && (*header).prefer_encrypt != 1i32 {
|
||||
if (*peerstate).prefer_encrypt == 1i32
|
||||
&& header.prefer_encrypt != EncryptPreference::Mutual
|
||||
{
|
||||
(*peerstate).degrade_event |= 0x1i32
|
||||
}
|
||||
(*peerstate).prefer_encrypt = (*header).prefer_encrypt;
|
||||
(*peerstate).prefer_encrypt = header.prefer_encrypt.to_i32().unwrap();
|
||||
(*peerstate).to_save |= 0x2i32
|
||||
}
|
||||
if (*peerstate).public_key.is_null() {
|
||||
@@ -229,15 +238,17 @@ pub unsafe fn dc_apeerstate_apply_header(
|
||||
|
||||
pub unsafe fn dc_apeerstate_apply_gossip(
|
||||
mut peerstate: *mut dc_apeerstate_t,
|
||||
gossip_header: *const dc_aheader_t,
|
||||
gossip_header: &Aheader,
|
||||
message_time: time_t,
|
||||
) {
|
||||
if peerstate.is_null()
|
||||
|| gossip_header.is_null()
|
||||
|| (*peerstate).addr.is_null()
|
||||
|| (*gossip_header).addr.is_null()
|
||||
|| (*(*gossip_header).public_key).binary.is_null()
|
||||
|| strcasecmp((*peerstate).addr, (*gossip_header).addr) != 0i32
|
||||
|| CStr::from_ptr((*peerstate).addr)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_lowercase()
|
||||
!= gossip_header.addr.to_lowercase()
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -259,16 +270,17 @@ pub unsafe fn dc_apeerstate_render_gossip_header(
|
||||
peerstate: *const dc_apeerstate_t,
|
||||
min_verified: libc::c_int,
|
||||
) -> *mut libc::c_char {
|
||||
let mut ret: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut autocryptheader: *mut dc_aheader_t = dc_aheader_new();
|
||||
if !(peerstate.is_null() || (*peerstate).addr.is_null()) {
|
||||
(*autocryptheader).prefer_encrypt = 0i32;
|
||||
(*autocryptheader).addr = dc_strdup((*peerstate).addr);
|
||||
(*autocryptheader).public_key = dc_key_ref(dc_apeerstate_peek_key(peerstate, min_verified));
|
||||
ret = dc_aheader_render(autocryptheader)
|
||||
let addr = CStr::from_ptr((*peerstate).addr).to_str().unwrap().into();
|
||||
let key = dc_key_ref(dc_apeerstate_peek_key(peerstate, min_verified));
|
||||
let header = Aheader::new(addr, key, EncryptPreference::NoPreference);
|
||||
let rendered = header.to_string();
|
||||
let rendered_c = CString::new(rendered).unwrap();
|
||||
|
||||
libc::strdup(rendered_c.as_ptr())
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
dc_aheader_unref(autocryptheader);
|
||||
ret
|
||||
}
|
||||
|
||||
pub unsafe fn dc_apeerstate_peek_key(
|
||||
|
||||
@@ -263,10 +263,7 @@ pub unsafe fn dc_array_new(initsize: size_t) -> *mut dc_array_t {
|
||||
dc_array_new_typed(0, initsize)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn dc_array_new_typed(
|
||||
type_0: libc::c_int,
|
||||
initsize: size_t,
|
||||
) -> *mut dc_array_t {
|
||||
pub unsafe fn dc_array_new_typed(type_0: libc::c_int, initsize: size_t) -> *mut dc_array_t {
|
||||
let mut array: *mut dc_array_t;
|
||||
array = calloc(1, ::std::mem::size_of::<dc_array_t>()) as *mut dc_array_t;
|
||||
if array.is_null() {
|
||||
|
||||
@@ -2279,7 +2279,7 @@ pub unsafe fn dc_chat_get_name(chat: *const dc_chat_t) -> *mut libc::c_char {
|
||||
dc_strdup((*chat).name)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn dc_chat_get_subtitle(chat: *const dc_chat_t) -> *mut libc::c_char {
|
||||
pub unsafe fn dc_chat_get_subtitle(chat: *const dc_chat_t) -> *mut libc::c_char {
|
||||
/* returns either the address or the number of chat members */
|
||||
let mut ret: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
|
||||
@@ -46,7 +46,7 @@ pub unsafe fn dc_marknoticed_contact(context: &dc_context_t, contact_id: uint32_
|
||||
}
|
||||
|
||||
// handle contacts
|
||||
pub unsafe extern "C" fn dc_may_be_valid_addr(addr: *const libc::c_char) -> bool {
|
||||
pub unsafe fn dc_may_be_valid_addr(addr: *const libc::c_char) -> bool {
|
||||
if addr.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
||||
202
src/dc_e2ee.rs
202
src/dc_e2ee.rs
@@ -1,3 +1,6 @@
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::str::FromStr;
|
||||
|
||||
use mmime::clist::*;
|
||||
use mmime::mailimf::*;
|
||||
use mmime::mailimf_types::*;
|
||||
@@ -53,11 +56,9 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
mut in_out_message: *mut mailmime,
|
||||
mut helper: *mut dc_e2ee_helper_t,
|
||||
) {
|
||||
let p_0: *mut libc::c_char;
|
||||
let current_block: u64;
|
||||
let mut col: libc::c_int = 0i32;
|
||||
let mut do_encrypt: libc::c_int = 0i32;
|
||||
let mut autocryptheader: *mut dc_aheader_t = dc_aheader_new();
|
||||
/*just a pointer into mailmime structure, must not be freed*/
|
||||
let imffields_unprotected: *mut mailimf_fields;
|
||||
let keyring: *mut dc_keyring_t = dc_keyring_new();
|
||||
@@ -73,42 +74,40 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
::std::mem::size_of::<dc_e2ee_helper_t>(),
|
||||
);
|
||||
}
|
||||
|
||||
if !(recipients_addr.is_null()
|
||||
|| in_out_message.is_null()
|
||||
|| !(*in_out_message).mm_parent.is_null()
|
||||
|| autocryptheader.is_null()
|
||||
|| keyring.is_null()
|
||||
|| sign_key.is_null()
|
||||
|| plain.is_null()
|
||||
|| helper.is_null())
|
||||
{
|
||||
/* libEtPan's pgp_encrypt_mime() takes the parent as the new root. We just expect the root as being given to this function. */
|
||||
(*autocryptheader).prefer_encrypt = 0i32;
|
||||
if 0 != dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
) {
|
||||
(*autocryptheader).prefer_encrypt = 1i32
|
||||
}
|
||||
(*autocryptheader).addr = dc_sqlite3_get_config(
|
||||
let prefer_encrypt = if 0
|
||||
!= dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
1,
|
||||
) {
|
||||
EncryptPreference::Mutual
|
||||
} else {
|
||||
EncryptPreference::NoPreference
|
||||
};
|
||||
|
||||
let addr = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !(*autocryptheader).addr.is_null() {
|
||||
if !(0
|
||||
== load_or_generate_self_public_key(
|
||||
context,
|
||||
(*autocryptheader).public_key,
|
||||
(*autocryptheader).addr,
|
||||
in_out_message,
|
||||
))
|
||||
{
|
||||
|
||||
let public_key = dc_key_new();
|
||||
if !addr.is_null() {
|
||||
if 0 != load_or_generate_self_public_key(context, public_key, addr, in_out_message) {
|
||||
/*only for random-seed*/
|
||||
if (*autocryptheader).prefer_encrypt == 1i32 || 0 != e2ee_guaranteed {
|
||||
if prefer_encrypt == EncryptPreference::Mutual || 0 != e2ee_guaranteed {
|
||||
do_encrypt = 1i32;
|
||||
let mut iter1: *mut clistiter;
|
||||
iter1 = (*recipients_addr).first;
|
||||
@@ -121,7 +120,7 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
as *const libc::c_char;
|
||||
let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context);
|
||||
let mut key_to_use: *mut dc_key_t = 0 as *mut dc_key_t;
|
||||
if !(strcasecmp(recipient_addr, (*autocryptheader).addr) == 0i32) {
|
||||
if !(strcasecmp(recipient_addr, addr) == 0i32) {
|
||||
if 0 != dc_apeerstate_load_by_addr(
|
||||
peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
@@ -148,11 +147,11 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
}
|
||||
}
|
||||
if 0 != do_encrypt {
|
||||
dc_keyring_add(keyring, (*autocryptheader).public_key);
|
||||
dc_keyring_add(keyring, public_key);
|
||||
if 0 == dc_key_load_self_private(
|
||||
context,
|
||||
sign_key,
|
||||
(*autocryptheader).addr,
|
||||
addr,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
) {
|
||||
do_encrypt = 0i32
|
||||
@@ -371,25 +370,24 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
match current_block {
|
||||
14181132614457621749 => {}
|
||||
_ => {
|
||||
p_0 = dc_aheader_render(autocryptheader);
|
||||
if !p_0.is_null() {
|
||||
mailimf_fields_add(
|
||||
imffields_unprotected,
|
||||
mailimf_field_new_custom(
|
||||
strdup(
|
||||
b"Autocrypt\x00" as *const u8 as *const libc::c_char,
|
||||
),
|
||||
p_0,
|
||||
),
|
||||
);
|
||||
}
|
||||
let addr = CStr::from_ptr(addr).to_str().unwrap();
|
||||
let aheader = Aheader::new(addr.into(), public_key, prefer_encrypt);
|
||||
let rendered = CString::new(aheader.to_string()).unwrap();
|
||||
|
||||
mailimf_fields_add(
|
||||
imffields_unprotected,
|
||||
mailimf_field_new_custom(
|
||||
strdup(b"Autocrypt\x00" as *const u8 as *const libc::c_char),
|
||||
libc::strdup(rendered.as_ptr()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dc_aheader_unref(autocryptheader);
|
||||
|
||||
dc_keyring_unref(keyring);
|
||||
dc_key_unref(sign_key);
|
||||
if !plain.is_null() {
|
||||
@@ -645,7 +643,6 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
(to detect parts that could not be decrypted, simply look for left "multipart/encrypted" MIME types */
|
||||
/*just a pointer into mailmime structure, must not be freed*/
|
||||
let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message);
|
||||
let mut autocryptheader: *mut dc_aheader_t = 0 as *mut dc_aheader_t;
|
||||
let mut message_time: time_t = 0i32 as time_t;
|
||||
let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context);
|
||||
let mut from: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
@@ -680,11 +677,10 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
}
|
||||
}
|
||||
}
|
||||
autocryptheader = dc_aheader_new_from_imffields(from, imffields);
|
||||
if !autocryptheader.is_null() {
|
||||
if 0 == dc_pgp_is_valid_key(context, (*autocryptheader).public_key) {
|
||||
dc_aheader_unref(autocryptheader);
|
||||
autocryptheader = 0 as *mut dc_aheader_t
|
||||
let mut autocryptheader = Aheader::from_imffields(from, imffields);
|
||||
if let Some(ref header) = autocryptheader {
|
||||
if 0 == dc_pgp_is_valid_key(context, header.public_key) {
|
||||
autocryptheader = None;
|
||||
}
|
||||
}
|
||||
if message_time > 0i32 as libc::c_long && !from.is_null() {
|
||||
@@ -693,8 +689,8 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
&context.sql.clone().read().unwrap(),
|
||||
from,
|
||||
) {
|
||||
if !autocryptheader.is_null() {
|
||||
dc_apeerstate_apply_header(peerstate, autocryptheader, message_time);
|
||||
if let Some(ref header) = autocryptheader {
|
||||
dc_apeerstate_apply_header(peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(peerstate, &context.sql.clone().read().unwrap(), 0i32);
|
||||
} else if message_time > (*peerstate).last_seen_autocrypt
|
||||
&& 0 == contains_report(in_out_message)
|
||||
@@ -702,8 +698,8 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
dc_apeerstate_degrade_encryption(peerstate, message_time);
|
||||
dc_apeerstate_save_to_db(peerstate, &context.sql.clone().read().unwrap(), 0i32);
|
||||
}
|
||||
} else if !autocryptheader.is_null() {
|
||||
dc_apeerstate_init_from_header(peerstate, autocryptheader, message_time);
|
||||
} else if let Some(ref header) = autocryptheader {
|
||||
dc_apeerstate_init_from_header(peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(peerstate, &context.sql.clone().read().unwrap(), 1i32);
|
||||
}
|
||||
}
|
||||
@@ -767,7 +763,7 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
if !gossip_headers.is_null() {
|
||||
mailimf_fields_free(gossip_headers);
|
||||
}
|
||||
dc_aheader_unref(autocryptheader);
|
||||
|
||||
dc_apeerstate_unref(peerstate);
|
||||
dc_keyring_unref(private_keyring);
|
||||
dc_keyring_unref(public_keyring_for_validate);
|
||||
@@ -801,66 +797,70 @@ unsafe fn update_gossip_peerstates(
|
||||
b"Autocrypt-Gossip\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0i32
|
||||
{
|
||||
let gossip_header: *mut dc_aheader_t = dc_aheader_new();
|
||||
if 0 != dc_aheader_set_from_string(gossip_header, (*optional_field).fld_value)
|
||||
&& 0 != dc_pgp_is_valid_key(context, (*gossip_header).public_key)
|
||||
{
|
||||
if recipients.is_null() {
|
||||
recipients = mailimf_get_recipients(imffields)
|
||||
}
|
||||
if !dc_hash_find(
|
||||
recipients,
|
||||
(*gossip_header).addr as *const libc::c_void,
|
||||
strlen((*gossip_header).addr) as libc::c_int,
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context);
|
||||
if 0 == dc_apeerstate_load_by_addr(
|
||||
peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
(*gossip_header).addr,
|
||||
) {
|
||||
dc_apeerstate_init_from_gossip(peerstate, gossip_header, message_time);
|
||||
dc_apeerstate_save_to_db(
|
||||
let value = CStr::from_ptr((*optional_field).fld_value)
|
||||
.to_str()
|
||||
.unwrap();
|
||||
let gossip_header = Aheader::from_str(value);
|
||||
if let Ok(ref header) = gossip_header {
|
||||
if 0 != dc_pgp_is_valid_key(context, header.public_key) {
|
||||
if recipients.is_null() {
|
||||
recipients = mailimf_get_recipients(imffields)
|
||||
}
|
||||
if !dc_hash_find(
|
||||
recipients,
|
||||
CString::new(header.addr.clone()).unwrap().as_ptr()
|
||||
as *const libc::c_void,
|
||||
header.addr.len() as i32,
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context);
|
||||
if 0 == dc_apeerstate_load_by_addr(
|
||||
peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
1i32,
|
||||
CString::new(header.addr.clone()).unwrap().as_ptr(),
|
||||
) {
|
||||
dc_apeerstate_init_from_gossip(peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(
|
||||
peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
1i32,
|
||||
);
|
||||
} else {
|
||||
dc_apeerstate_apply_gossip(peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(
|
||||
peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
0i32,
|
||||
);
|
||||
}
|
||||
if 0 != (*peerstate).degrade_event {
|
||||
dc_handle_degrade_event(context, peerstate);
|
||||
}
|
||||
dc_apeerstate_unref(peerstate);
|
||||
if gossipped_addr.is_null() {
|
||||
gossipped_addr =
|
||||
malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;
|
||||
dc_hash_init(gossipped_addr, 3i32, 1i32);
|
||||
}
|
||||
dc_hash_insert(
|
||||
gossipped_addr,
|
||||
CString::new(header.addr.clone()).unwrap().as_ptr()
|
||||
as *const libc::c_void,
|
||||
header.addr.len() as libc::c_int,
|
||||
1i32 as *mut libc::c_void,
|
||||
);
|
||||
} else {
|
||||
dc_apeerstate_apply_gossip(peerstate, gossip_header, message_time);
|
||||
dc_apeerstate_save_to_db(
|
||||
peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
b"Ignoring gossipped \"%s\" as the address is not in To/Cc list.\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
CString::new(header.addr.clone()).unwrap().as_ptr(),
|
||||
);
|
||||
}
|
||||
if 0 != (*peerstate).degrade_event {
|
||||
dc_handle_degrade_event(context, peerstate);
|
||||
}
|
||||
dc_apeerstate_unref(peerstate);
|
||||
if gossipped_addr.is_null() {
|
||||
gossipped_addr =
|
||||
malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;
|
||||
dc_hash_init(gossipped_addr, 3i32, 1i32);
|
||||
}
|
||||
dc_hash_insert(
|
||||
gossipped_addr,
|
||||
(*gossip_header).addr as *const libc::c_void,
|
||||
strlen((*gossip_header).addr) as libc::c_int,
|
||||
1i32 as *mut libc::c_void,
|
||||
);
|
||||
} else {
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
b"Ignoring gossipped \"%s\" as the address is not in To/Cc list.\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
(*gossip_header).addr,
|
||||
);
|
||||
}
|
||||
}
|
||||
dc_aheader_unref(gossip_header);
|
||||
}
|
||||
}
|
||||
cur1 = if !cur1.is_null() {
|
||||
|
||||
@@ -224,7 +224,7 @@ pub unsafe fn dc_hash_insert(
|
||||
|
||||
/* Link an element into the hash table
|
||||
*/
|
||||
unsafe extern "C" fn insertElement(
|
||||
unsafe fn insertElement(
|
||||
mut pH: *mut dc_hash_t,
|
||||
mut pEntry: *mut _ht,
|
||||
mut pNew: *mut dc_hashelem_t,
|
||||
|
||||
@@ -303,7 +303,7 @@ unsafe fn dc_suspend_smtp_thread(context: &dc_context_t, suspend: libc::c_int) {
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe extern "C" fn dc_job_do_DC_JOB_SEND(context: &dc_context_t, job: &mut dc_job_t) {
|
||||
unsafe fn dc_job_do_DC_JOB_SEND(context: &dc_context_t, job: &mut dc_job_t) {
|
||||
let mut current_block: u64;
|
||||
let mut filename: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut buf: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
|
||||
@@ -86,10 +86,7 @@ pub unsafe fn dc_jobthread_suspend(
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn dc_jobthread_interrupt_idle(
|
||||
context: &dc_context_t,
|
||||
jobthread: &dc_jobthread_t,
|
||||
) {
|
||||
pub unsafe fn dc_jobthread_interrupt_idle(context: &dc_context_t, jobthread: &dc_jobthread_t) {
|
||||
{
|
||||
jobthread.state.clone().0.lock().unwrap().jobs_needed = 1;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ pub unsafe fn dc_key_set_from_key(key: *mut dc_key_t, o: *const dc_key_t) -> lib
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe extern "C" fn dc_key_set_from_stmt(
|
||||
pub unsafe fn dc_key_set_from_stmt(
|
||||
key: *mut dc_key_t,
|
||||
stmt: *mut sqlite3_stmt,
|
||||
index: libc::c_int,
|
||||
@@ -297,11 +297,8 @@ pub unsafe fn dc_key_load_self_private(
|
||||
success
|
||||
}
|
||||
|
||||
/* the result must be freed */
|
||||
pub fn dc_key_render_base64(key: *const dc_key_t, break_every: usize) -> *mut libc::c_char {
|
||||
if key.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
pub fn dc_key_render_base64_string(key: *const dc_key_t, break_every: usize) -> String {
|
||||
assert!(!key.is_null(), "missing key");
|
||||
|
||||
let key = unsafe { *key };
|
||||
let bytes = unsafe { slice::from_raw_parts(key.binary as *const u8, key.bytes as usize) };
|
||||
@@ -318,7 +315,7 @@ pub fn dc_key_render_base64(key: *const dc_key_t, break_every: usize) -> *mut li
|
||||
};
|
||||
|
||||
let encoded = base64::encode(&buf);
|
||||
let res = encoded
|
||||
encoded
|
||||
.as_bytes()
|
||||
.chunks(break_every)
|
||||
.fold(String::new(), |mut res, buf| {
|
||||
@@ -326,8 +323,14 @@ pub fn dc_key_render_base64(key: *const dc_key_t, break_every: usize) -> *mut li
|
||||
res += unsafe { std::str::from_utf8_unchecked(buf) };
|
||||
res += " ";
|
||||
res
|
||||
});
|
||||
})
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/* the result must be freed */
|
||||
pub fn dc_key_render_base64(key: *const dc_key_t, break_every: usize) -> *mut libc::c_char {
|
||||
let res = dc_key_render_base64_string(key, break_every);
|
||||
let res_c = CString::new(res.trim()).unwrap();
|
||||
|
||||
// need to use strdup to allocate the result with malloc
|
||||
|
||||
@@ -129,7 +129,7 @@ unsafe fn schedule_MAYBE_SEND_LOCATIONS(context: &dc_context_t, flags: libc::c_i
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn dc_is_sending_locations_to_chat(
|
||||
pub unsafe fn dc_is_sending_locations_to_chat(
|
||||
context: &dc_context_t,
|
||||
chat_id: uint32_t,
|
||||
) -> libc::c_int {
|
||||
|
||||
@@ -469,7 +469,7 @@ unsafe fn jsondup(json: *const libc::c_char, tok: *mut jsmntok_t) -> *mut libc::
|
||||
strdup(b"\x00" as *const u8 as *const libc::c_char)
|
||||
}
|
||||
|
||||
unsafe extern "C" fn jsoneq(
|
||||
unsafe fn jsoneq(
|
||||
json: *const libc::c_char,
|
||||
tok: *mut jsmntok_t,
|
||||
s: *const libc::c_char,
|
||||
|
||||
@@ -20,10 +20,7 @@ pub type dc_saxparser_starttag_cb_t = Option<
|
||||
unsafe fn(_: *mut libc::c_void, _: *const libc::c_char, _: *mut *mut libc::c_char) -> (),
|
||||
>;
|
||||
|
||||
pub unsafe extern "C" fn dc_saxparser_init(
|
||||
mut saxparser: *mut dc_saxparser_t,
|
||||
userdata: *mut libc::c_void,
|
||||
) {
|
||||
pub unsafe fn dc_saxparser_init(mut saxparser: *mut dc_saxparser_t, userdata: *mut libc::c_void) {
|
||||
(*saxparser).userdata = userdata;
|
||||
(*saxparser).starttag_cb = Some(def_starttag_cb);
|
||||
(*saxparser).endtag_cb = Some(def_endtag_cb);
|
||||
|
||||
@@ -24,7 +24,7 @@ pub fn isdigit(mut _c: libc::c_int) -> libc::c_int {
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn dc_urlencode(to_encode: *const libc::c_char) -> *mut libc::c_char {
|
||||
pub unsafe fn dc_urlencode(to_encode: *const libc::c_char) -> *mut libc::c_char {
|
||||
let mut pstr: *const libc::c_char = to_encode;
|
||||
if to_encode.is_null() {
|
||||
return dc_strdup(b"\x00" as *const u8 as *const libc::c_char);
|
||||
|
||||
@@ -266,7 +266,7 @@ pub unsafe fn dc_binary_to_uc_hex(buf: *const uint8_t, bytes: size_t) -> *mut li
|
||||
}
|
||||
|
||||
/* remove all \r characters from string */
|
||||
pub unsafe extern "C" fn dc_remove_cr_chars(buf: *mut libc::c_char) {
|
||||
pub unsafe fn dc_remove_cr_chars(buf: *mut libc::c_char) {
|
||||
/* search for first `\r` */
|
||||
let mut p1: *const libc::c_char = buf;
|
||||
while 0 != *p1 {
|
||||
|
||||
212
tests/stress.rs
212
tests/stress.rs
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user