mirror of
https://github.com/chatmail/core.git
synced 2026-07-08 00:15:13 +03:00
Compare commits
2 Commits
1.0.0-beta
...
fix_1007
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9c0492fbd | ||
|
|
72e128db2e |
29
CHANGELOG.md
29
CHANGELOG.md
@@ -1,34 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## 1.0.0-beta.16
|
||||
|
||||
- alleviate login problems with providers which only
|
||||
support RSA1024 keys by switching back from Rustls
|
||||
to native-tls, by using the new async-email/async-native-tls
|
||||
crate from @dignifiedquire. thanks @link2xt.
|
||||
|
||||
- introduce per-contact profile images to send out
|
||||
own profile image heuristically, and fix sending
|
||||
out of profile images in "in-prepare" groups.
|
||||
this also extends the Chat-spec that is maintained
|
||||
in core to specify Chat-Group-Image and Chat-Group-Avatar
|
||||
headers. thanks @r10s and @hpk42.
|
||||
|
||||
- fix merging of protected headers from the encrypted
|
||||
to the unencrypted parts, now not happening recursively
|
||||
anymore. thanks @hpk and @r10s
|
||||
|
||||
- fix/optimize autocrypt gossip headers to only get
|
||||
sent when there are more than 2 people in a chat.
|
||||
thanks @link2xt
|
||||
|
||||
- fix displayname to use the authenticated name
|
||||
when available (displayname as coming from contacts
|
||||
themselves). thanks @simon-laux
|
||||
|
||||
- introduce preliminary support for offline autoconfig
|
||||
for nauta provider. thanks @hpk42 @r10s
|
||||
|
||||
## 1.0.0-beta.15
|
||||
|
||||
- fix #994 attachment appeared doubled in chats (and where actually
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat"
|
||||
version = "1.0.0-beta.16"
|
||||
version = "1.0.0-beta.15"
|
||||
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
|
||||
edition = "2018"
|
||||
license = "MPL"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat_ffi"
|
||||
version = "1.0.0-beta.16"
|
||||
version = "1.0.0-beta.15"
|
||||
description = "Deltachat FFI"
|
||||
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
|
||||
edition = "2018"
|
||||
|
||||
@@ -715,12 +715,6 @@ class TestOnlineAccount:
|
||||
assert msg_back.text == "message-back"
|
||||
assert msg_back.is_encrypted()
|
||||
|
||||
# Test that we do not gossip peer keys in 1-to-1 chat,
|
||||
# as it makes no sense to gossip to peers their own keys.
|
||||
# Gossip is only sent in encrypted messages,
|
||||
# and we sent encrypted msg_back right above.
|
||||
assert chat2b.get_summary()["gossiped_timestamp"] == 0
|
||||
|
||||
lp.sec("create group chat with two members, one of which has no encrypt state")
|
||||
chat = ac1.create_group_chat("encryption test")
|
||||
chat.add_contact(ac1.create_contact(ac2.get_config("addr")))
|
||||
|
||||
40
src/chat.rs
40
src/chat.rs
@@ -35,6 +35,7 @@ pub struct Chat {
|
||||
pub grpid: String,
|
||||
blocked: Blocked,
|
||||
pub param: Params,
|
||||
pub gossiped_timestamp: i64,
|
||||
is_sending_locations: bool,
|
||||
}
|
||||
|
||||
@@ -43,7 +44,7 @@ impl Chat {
|
||||
pub fn load_from_db(context: &Context, chat_id: u32) -> Result<Self, Error> {
|
||||
let res = context.sql.query_row(
|
||||
"SELECT c.id,c.type,c.name, c.grpid,c.param,c.archived, \
|
||||
c.blocked, c.locations_send_until \
|
||||
c.blocked, c.gossiped_timestamp, c.locations_send_until \
|
||||
FROM chats c WHERE c.id=?;",
|
||||
params![chat_id as i32],
|
||||
|row| {
|
||||
@@ -55,7 +56,8 @@ impl Chat {
|
||||
param: row.get::<_, String>(4)?.parse().unwrap_or_default(),
|
||||
archived: row.get(5)?,
|
||||
blocked: row.get::<_, Option<_>>(6)?.unwrap_or_default(),
|
||||
is_sending_locations: row.get(7)?,
|
||||
gossiped_timestamp: row.get(7)?,
|
||||
is_sending_locations: row.get(8)?,
|
||||
};
|
||||
|
||||
Ok(c)
|
||||
@@ -214,10 +216,6 @@ impl Chat {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_gossiped_timestamp(&self, context: &Context) -> i64 {
|
||||
get_gossiped_timestamp(context, self.id)
|
||||
}
|
||||
|
||||
pub fn get_color(&self, context: &Context) -> u32 {
|
||||
let mut color = 0;
|
||||
|
||||
@@ -1467,7 +1465,7 @@ pub(crate) fn add_contact_to_chat_ex(
|
||||
let contact = Contact::get_by_id(context, contact_id)?;
|
||||
let mut msg = Message::default();
|
||||
|
||||
reset_gossiped_timestamp(context, chat_id)?;
|
||||
reset_gossiped_timestamp(context, chat_id);
|
||||
|
||||
/*this also makes sure, not contacts are added to special or normal chats*/
|
||||
let mut chat = Chat::load_from_db(context, chat_id)?;
|
||||
@@ -1565,28 +1563,12 @@ fn real_group_exists(context: &Context, chat_id: u32) -> bool {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn reset_gossiped_timestamp(context: &Context, chat_id: u32) -> crate::sql::Result<()> {
|
||||
set_gossiped_timestamp(context, chat_id, 0)
|
||||
pub fn reset_gossiped_timestamp(context: &Context, chat_id: u32) {
|
||||
set_gossiped_timestamp(context, chat_id, 0);
|
||||
}
|
||||
|
||||
/// Get timestamp of the last gossip sent in the chat.
|
||||
/// Zero return value means that gossip was never sent.
|
||||
pub fn get_gossiped_timestamp(context: &Context, chat_id: u32) -> i64 {
|
||||
context
|
||||
.sql
|
||||
.query_get_value::<_, i64>(
|
||||
context,
|
||||
"SELECT gossiped_timestamp FROM chats WHERE id=?;",
|
||||
params![chat_id as i32],
|
||||
)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn set_gossiped_timestamp(
|
||||
context: &Context,
|
||||
chat_id: u32,
|
||||
timestamp: i64,
|
||||
) -> crate::sql::Result<()> {
|
||||
// Should return Result
|
||||
pub fn set_gossiped_timestamp(context: &Context, chat_id: u32, timestamp: i64) {
|
||||
if 0 != chat_id {
|
||||
info!(
|
||||
context,
|
||||
@@ -1599,6 +1581,7 @@ pub fn set_gossiped_timestamp(
|
||||
"UPDATE chats SET gossiped_timestamp=? WHERE id=?;",
|
||||
params![timestamp, chat_id as i32],
|
||||
)
|
||||
.ok();
|
||||
} else {
|
||||
info!(
|
||||
context,
|
||||
@@ -1610,6 +1593,7 @@ pub fn set_gossiped_timestamp(
|
||||
"UPDATE chats SET gossiped_timestamp=?;",
|
||||
params![timestamp],
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2018,7 +2002,7 @@ pub fn get_info_json(context: &Context, chat_id: u32) -> Result<String, Error> {
|
||||
"name": chat.name,
|
||||
"archived": chat.archived,
|
||||
"param": chat.param.to_string(),
|
||||
"gossiped_timestamp": chat.get_gossiped_timestamp(context),
|
||||
"gossiped_timestamp": chat.gossiped_timestamp,
|
||||
"is_sending_locations": chat.is_sending_locations,
|
||||
"color": chat.get_color(context),
|
||||
"profile_image": profile_image,
|
||||
|
||||
@@ -92,11 +92,9 @@ pub fn JobConfigureImap(context: &Context) {
|
||||
let mut param_domain = "undefined.undefined".to_owned();
|
||||
let mut param_addr_urlencoded: String =
|
||||
"Internal Error: this value should never be used".to_owned();
|
||||
let mut keep_flags = 0;
|
||||
|
||||
const STEP_12_USE_AUTOCONFIG: u8 = 12;
|
||||
const STEP_13_AFTER_AUTOCONFIG: u8 = 13;
|
||||
let mut keep_flags = std::i32::MAX;
|
||||
|
||||
const STEP_3_INDEX: u8 = 13;
|
||||
let mut step_counter: u8 = 0;
|
||||
while !context.shall_stop_ongoing() {
|
||||
step_counter += 1;
|
||||
@@ -112,7 +110,7 @@ pub fn JobConfigureImap(context: &Context) {
|
||||
}
|
||||
// Step 1: Load the parameters and check email-address and password
|
||||
2 => {
|
||||
if 0 != param.server_flags & DC_LP_AUTH_OAUTH2 {
|
||||
if 0 != param.server_flags & 0x2 {
|
||||
// the used oauth2 addr may differ, check this.
|
||||
// if dc_get_oauth2_addr() is not available in the oauth2 implementation,
|
||||
// just use the given one.
|
||||
@@ -148,25 +146,43 @@ pub fn JobConfigureImap(context: &Context) {
|
||||
4 => {
|
||||
progress!(context, 200);
|
||||
|
||||
if param.mail_server.is_empty()
|
||||
// special case nauta.cu (this should eventually come
|
||||
// from our provider-db): enforce non-tls cleartext
|
||||
// settings and and skip all autoconfig which this
|
||||
// provider does not offer anyway.
|
||||
if param.addr.ends_with("@nauta.cu") {
|
||||
let mut p = LoginParam::new();
|
||||
|
||||
p.addr = param.addr.clone();
|
||||
p.mail_user = param.addr.clone();
|
||||
p.mail_pw = param.mail_pw.clone();
|
||||
p.mail_port = 143;
|
||||
p.imap_certificate_checks = CertificateChecks::AcceptInvalidCertificates;
|
||||
|
||||
p.send_user = param.addr.clone();
|
||||
p.send_pw = param.mail_pw.clone();
|
||||
p.send_port = 25;
|
||||
p.smtp_certificate_checks = CertificateChecks::AcceptInvalidCertificates;
|
||||
p.server_flags = DC_LP_AUTH_NORMAL as i32
|
||||
| DC_LP_IMAP_SOCKET_PLAIN as i32
|
||||
| DC_LP_SMTP_SOCKET_PLAIN as i32;
|
||||
|
||||
// pretend we did autoconfig, to prevent further tries
|
||||
param_autoconfig = Some(p);
|
||||
step_counter = 12 - 1;
|
||||
} else if param.mail_server.is_empty()
|
||||
&& param.mail_port == 0
|
||||
/*&¶m.mail_user.is_empty() -- the user can enter a loginname which is used by autoconfig then */
|
||||
&& param.send_server.is_empty()
|
||||
&& param.send_port == 0
|
||||
&& param.send_user.is_empty()
|
||||
/*&¶m.send_pw.is_empty() -- the password cannot be auto-configured and is no criterion for autoconfig or not */
|
||||
&& (param.server_flags & !DC_LP_AUTH_OAUTH2) == 0
|
||||
&& param.server_flags & !0x2 == 0
|
||||
{
|
||||
// no advanced parameters entered by the user: query provider-database or do Autoconfig
|
||||
keep_flags = param.server_flags & DC_LP_AUTH_OAUTH2;
|
||||
if let Some(new_param) = get_offline_autoconfig(context, ¶m) {
|
||||
// got parameters from our provider-database, skip Autoconfig, preserve the OAuth2 setting
|
||||
param_autoconfig = Some(new_param);
|
||||
step_counter = STEP_12_USE_AUTOCONFIG - 1; // minus one as step_counter is increased on next loop
|
||||
}
|
||||
keep_flags = param.server_flags & 0x2;
|
||||
} else {
|
||||
// advanced parameters entered by the user: skip Autoconfig
|
||||
step_counter = STEP_13_AFTER_AUTOCONFIG - 1; // minus one as step_counter is increased on next loop
|
||||
// Autoconfig is not needed so skip it.
|
||||
step_counter = STEP_3_INDEX - 1;
|
||||
}
|
||||
true
|
||||
}
|
||||
@@ -251,10 +267,8 @@ pub fn JobConfigureImap(context: &Context) {
|
||||
}
|
||||
true
|
||||
}
|
||||
/* C. Do we have any autoconfig result?
|
||||
If you change the match-number here, also update STEP_12_COPY_AUTOCONFIG above
|
||||
*/
|
||||
STEP_12_USE_AUTOCONFIG => {
|
||||
/* C. Do we have any result? */
|
||||
12 => {
|
||||
progress!(context, 500);
|
||||
if let Some(ref cfg) = param_autoconfig {
|
||||
info!(context, "Got autoconfig: {}", &cfg);
|
||||
@@ -274,8 +288,8 @@ pub fn JobConfigureImap(context: &Context) {
|
||||
true
|
||||
}
|
||||
// Step 3: Fill missing fields with defaults
|
||||
// If you change the match-number here, also update STEP_13_AFTER_AUTOCONFIG above
|
||||
STEP_13_AFTER_AUTOCONFIG => {
|
||||
13 => {
|
||||
// if you move this, don't forget to update STEP_3_INDEX, too
|
||||
if param.mail_server.is_empty() {
|
||||
param.mail_server = format!("imap.{}", param_domain,)
|
||||
}
|
||||
@@ -441,42 +455,6 @@ pub fn JobConfigureImap(context: &Context) {
|
||||
progress!(context, if success { 1000 } else { 0 });
|
||||
}
|
||||
|
||||
fn get_offline_autoconfig(context: &Context, param: &LoginParam) -> Option<LoginParam> {
|
||||
// XXX we don't have https://github.com/deltachat/provider-db APIs
|
||||
// integrated yet but we'll already add nauta as a first use case, also
|
||||
// showing what we need from provider-db in the future.
|
||||
info!(
|
||||
context,
|
||||
"checking internal provider-info for offline autoconfig"
|
||||
);
|
||||
|
||||
if param.addr.ends_with("@nauta.cu") {
|
||||
let mut p = LoginParam::new();
|
||||
|
||||
p.addr = param.addr.clone();
|
||||
p.mail_server = "imap.nauta.cu".to_string();
|
||||
p.mail_user = param.addr.clone();
|
||||
p.mail_pw = param.mail_pw.clone();
|
||||
p.mail_port = 143;
|
||||
p.imap_certificate_checks = CertificateChecks::AcceptInvalidCertificates;
|
||||
|
||||
p.send_server = "smtp.nauta.cu".to_string();
|
||||
p.send_user = param.addr.clone();
|
||||
p.send_pw = param.mail_pw.clone();
|
||||
p.send_port = 25;
|
||||
p.smtp_certificate_checks = CertificateChecks::AcceptInvalidCertificates;
|
||||
p.server_flags = DC_LP_AUTH_NORMAL as i32
|
||||
| DC_LP_IMAP_SOCKET_STARTTLS as i32
|
||||
| DC_LP_SMTP_SOCKET_STARTTLS as i32;
|
||||
|
||||
info!(context, "found offline autoconfig: {}", p);
|
||||
Some(p)
|
||||
} else {
|
||||
info!(context, "no offline autoconfig found");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn try_imap_connections(
|
||||
context: &Context,
|
||||
mut param: &mut LoginParam,
|
||||
@@ -618,7 +596,6 @@ fn try_smtp_one_param(context: &Context, param: &LoginParam) -> Option<bool> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::config::*;
|
||||
use crate::configure::JobConfigureImap;
|
||||
use crate::test_utils::*;
|
||||
@@ -632,19 +609,4 @@ mod tests {
|
||||
t.ctx.set_config(Config::MailPw, Some("123456")).unwrap();
|
||||
JobConfigureImap(&t.ctx);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_offline_autoconfig() {
|
||||
let context = dummy_context().ctx;
|
||||
|
||||
let mut params = LoginParam::new();
|
||||
params.addr = "someone123@example.org".to_string();
|
||||
assert!(get_offline_autoconfig(&context, ¶ms).is_none());
|
||||
|
||||
let mut params = LoginParam::new();
|
||||
params.addr = "someone123@nauta.cu".to_string();
|
||||
let found_params = get_offline_autoconfig(&context, ¶ms).unwrap();
|
||||
assert_eq!(found_params.mail_server, "imap.nauta.cu".to_string());
|
||||
assert_eq!(found_params.send_server, "smtp.nauta.cu".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -745,9 +745,6 @@ impl Contact {
|
||||
if !self.name.is_empty() {
|
||||
return &self.name;
|
||||
}
|
||||
if !self.authname.is_empty() {
|
||||
return &self.authname;
|
||||
}
|
||||
&self.addr
|
||||
}
|
||||
|
||||
|
||||
@@ -1085,7 +1085,7 @@ fn create_or_lookup_group(
|
||||
}
|
||||
}
|
||||
send_EVENT_CHAT_MODIFIED = true;
|
||||
chat::reset_gossiped_timestamp(context, chat_id)?;
|
||||
chat::reset_gossiped_timestamp(context, chat_id);
|
||||
}
|
||||
|
||||
if send_EVENT_CHAT_MODIFIED {
|
||||
|
||||
@@ -678,7 +678,7 @@ pub fn job_send_msg(context: &Context, msg_id: MsgId) -> Result<(), Error> {
|
||||
}
|
||||
|
||||
if rendered_msg.is_gossiped {
|
||||
chat::set_gossiped_timestamp(context, msg.chat_id, time())?;
|
||||
chat::set_gossiped_timestamp(context, msg.chat_id, time());
|
||||
}
|
||||
|
||||
if 0 != rendered_msg.last_added_location_id {
|
||||
|
||||
@@ -102,7 +102,19 @@ impl LoginParam {
|
||||
};
|
||||
|
||||
let key = format!("{}server_flags", prefix);
|
||||
let server_flags = sql.get_raw_config_int(context, key).unwrap_or_default();
|
||||
let mut server_flags = sql.get_raw_config_int(context, key).unwrap_or_default();
|
||||
|
||||
// XXX special case nauta.cu: enforce cleartext instead of TLS because
|
||||
// Rust-TLS does not support nauta.cu's RSA1024 TLS cert.
|
||||
// see https://github.com/deltachat/deltachat-core-rust/issues/1007
|
||||
if mail_server.ends_with(".nauta.cu") {
|
||||
server_flags &= !0x300; // clear out IMAP_SSL/STARTTLS
|
||||
server_flags |= 0x400; // set IMAP_PLAIN
|
||||
}
|
||||
if send_server.ends_with(".nauta.cu") {
|
||||
server_flags &= !0x30000; // clear out SMTP_SSL/STARTTLS
|
||||
server_flags |= 0x40000; // set SMTP_PLAIN
|
||||
}
|
||||
|
||||
LoginParam {
|
||||
addr,
|
||||
|
||||
@@ -304,8 +304,9 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
|
||||
Loaded::Message => {
|
||||
let chat = self.chat.as_ref().unwrap();
|
||||
// beside key- and member-changes, force re-gossip every 48 hours
|
||||
let gossiped_timestamp = chat.get_gossiped_timestamp(self.context);
|
||||
if gossiped_timestamp == 0 || (gossiped_timestamp + (2 * 24 * 60 * 60)) > time() {
|
||||
if chat.gossiped_timestamp == 0
|
||||
|| (chat.gossiped_timestamp + (2 * 24 * 60 * 60)) > time()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -462,6 +463,7 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
|
||||
}
|
||||
|
||||
let min_verified = self.min_verified();
|
||||
let do_gossip = self.should_do_gossip();
|
||||
let grpimage = self.grpimage();
|
||||
let force_plaintext = self.should_force_plaintext();
|
||||
let subject_str = self.subject_str();
|
||||
@@ -509,17 +511,14 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
|
||||
unprotected_headers.push(Header::new_with_value("To".into(), to).unwrap());
|
||||
unprotected_headers.push(Header::new_with_value("From".into(), vec![from]).unwrap());
|
||||
|
||||
let mut is_gossiped = false;
|
||||
|
||||
let outer_message = if is_encrypted {
|
||||
// Add gossip headers in chats with multiple recipients
|
||||
if peerstates.len() > 1 && self.should_do_gossip() {
|
||||
// Add gossip headers
|
||||
if do_gossip {
|
||||
for peerstate in peerstates.iter().filter_map(|(state, _)| state.as_ref()) {
|
||||
if peerstate.peek_key(min_verified).is_some() {
|
||||
if let Some(header) = peerstate.render_gossip_header(min_verified) {
|
||||
message =
|
||||
message.header(Header::new("Autocrypt-Gossip".into(), header));
|
||||
is_gossiped = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -600,6 +599,8 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
|
||||
message
|
||||
};
|
||||
|
||||
let is_gossiped = is_encrypted && do_gossip && !peerstates.is_empty();
|
||||
|
||||
let MimeFactory {
|
||||
recipients_addr,
|
||||
from_addr,
|
||||
|
||||
@@ -417,7 +417,7 @@ impl<'a> Peerstate<'a> {
|
||||
&self.addr,
|
||||
],
|
||||
)?;
|
||||
reset_gossiped_timestamp(self.context, 0)?;
|
||||
reset_gossiped_timestamp(self.context, 0);
|
||||
} else if self.to_save == Some(ToSave::Timestamps) {
|
||||
sql::execute(
|
||||
self.context,
|
||||
|
||||
Reference in New Issue
Block a user