From 243c035b03d6d44e4d5f8b2369923d9c5fb3da98 Mon Sep 17 00:00:00 2001 From: link2xt Date: Fri, 7 Jul 2023 21:56:59 +0000 Subject: [PATCH 001/102] chore: spellcheck --- src/chat.rs | 2 +- src/mimeparser.rs | 2 +- src/tools.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/chat.rs b/src/chat.rs index db8a955d7..950eb9e90 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -2202,7 +2202,7 @@ pub async fn send_msg_sync(context: &Context, chat_id: ChatId, msg: &mut Message } async fn send_msg_inner(context: &Context, chat_id: ChatId, msg: &mut Message) -> Result { - // protect all system messages againts RTLO attacks + // protect all system messages against RTLO attacks if msg.is_system_message() { msg.text = strip_rtlo_characters(&msg.text); } diff --git a/src/mimeparser.rs b/src/mimeparser.rs index e6e02335a..a9a039685 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -1892,7 +1892,7 @@ fn get_mime_type(mail: &mailparse::ParsedMail<'_>) -> Result<(Mime, Viewtype)> { } else { // Enacapsulated messages, see // Also used as part "message/disposition-notification" of "multipart/report", which, however, will - // be handled separatedly. + // be handled separately. // I've not seen any messages using this, so we do not attach these parts (maybe they're used to attach replies, // which are unwanted at all). // For now, we skip these parts at all; if desired, we could return DcMimeType::File/DC_MSG_File diff --git a/src/tools.rs b/src/tools.rs index 8c397255f..b0ba5d6f7 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -702,7 +702,7 @@ pub(crate) fn buf_decompress(buf: &[u8]) -> Result> { } const RTLO_CHARACTERS: [char; 5] = ['\u{202A}', '\u{202B}', '\u{202C}', '\u{202D}', '\u{202E}']; -/// This method strips all occurances of the RTLO Unicode character. +/// This method strips all occurrences of the RTLO Unicode character. /// [Why is this needed](https://github.com/deltachat/deltachat-core-rust/issues/3479)? pub(crate) fn strip_rtlo_characters(input_str: &str) -> String { input_str.replace(|char| RTLO_CHARACTERS.contains(&char), "") From 9cd000c4f2afc223ea92dbb244c92dffb3effbff Mon Sep 17 00:00:00 2001 From: Hocuri Date: Sun, 9 Jul 2023 14:06:45 +0200 Subject: [PATCH 002/102] feat: Verified 1:1 chats (#4315) Implement #4188 BREAKING CHANGE: Remove unused DC_STR_PROTECTION_(EN)ABLED* strings BREAKING CHANGE: Remove unused dc_set_chat_protection() --- deltachat-ffi/deltachat.h | 87 ++- deltachat-ffi/src/lib.rs | 36 +- deltachat-repl/src/cmdline.rs | 29 +- node/lib/context.ts | 17 - node/src/module.c | 13 - src/chat.rs | 270 +++++----- src/config.rs | 10 + src/context.rs | 6 + src/lib.rs | 2 +- src/mimefactory.rs | 12 +- src/peerstate.rs | 25 + src/receive_imf.rs | 189 +++---- src/securejoin.rs | 63 ++- src/securejoin/bob.rs | 8 + src/stock_str.rs | 114 ++-- src/test_utils.rs | 68 ++- src/tests.rs | 1 + src/tests/aeap.rs | 15 +- src/tests/verified_chats.rs | 508 ++++++++++++++++++ test-data/golden/test_outgoing_mua_msg | 7 + ...test_verified_oneonone_chat_enable_disable | 12 + 21 files changed, 1037 insertions(+), 455 deletions(-) create mode 100644 src/tests/verified_chats.rs create mode 100644 test-data/golden/test_outgoing_mua_msg create mode 100644 test-data/golden/test_verified_oneonone_chat_enable_disable diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 5dcd263e2..22e6df1e2 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -485,6 +485,13 @@ char* dc_get_blobdir (const dc_context_t* context); * to not mess up with non-delivery-reports or read-receipts. * 0=no limit (default). * Changes affect future messages only. + * - `verified_one_on_one_chats` = Feature flag for verified 1:1 chats; the UI should set it + * to 1 if it supports verified 1:1 chats. + * Regardless of this setting, `dc_chat_is_protected()` returns true while the key is verified, + * and when the key changes, an info message is posted into the chat. + * 0=Nothing else happens when the key changes. + * 1=After the key changed, `dc_chat_can_send()` returns false and `dc_chat_is_protection_broken()` returns true + * until `dc_accept_chat()` is called. * - `ui.*` = All keys prefixed by `ui.` can be used by the user-interfaces for system-specific purposes. * The prefix should be followed by the system and maybe subsystem, * e.g. `ui.desktop.foo`, `ui.desktop.linux.bar`, `ui.android.foo`, `ui.dc40.bar`, `ui.bot.simplebot.baz`. @@ -1470,24 +1477,6 @@ dc_array_t* dc_get_chat_media (dc_context_t* context, uint32_t ch uint32_t dc_get_next_media (dc_context_t* context, uint32_t msg_id, int dir, int msg_type, int msg_type2, int msg_type3); -/** - * Enable or disable protection against active attacks. - * To enable protection, it is needed that all members are verified; - * if this condition is met, end-to-end-encryption is always enabled - * and only the verified keys are used. - * - * Sends out #DC_EVENT_CHAT_MODIFIED on changes - * and #DC_EVENT_MSGS_CHANGED if a status message was sent. - * - * @memberof dc_context_t - * @param context The context object as returned from dc_context_new(). - * @param chat_id The ID of the chat to change the protection for. - * @param protect 1=protect chat, 0=unprotect chat - * @return 1=success, 0=error, e.g. some members may be unverified - */ -int dc_set_chat_protection (dc_context_t* context, uint32_t chat_id, int protect); - - /** * Set chat visibility to pinned, archived or normal. * @@ -3712,7 +3701,6 @@ int dc_chat_can_send (const dc_chat_t* chat); * Check if a chat is protected. * Protected chats contain only verified members and encryption is always enabled. * Protected chats are created using dc_create_group_chat() by setting the 'protect' parameter to 1. - * The status can be changed using dc_set_chat_protection(). * * @memberof dc_chat_t * @param chat The chat object. @@ -3721,6 +3709,26 @@ int dc_chat_can_send (const dc_chat_t* chat); int dc_chat_is_protected (const dc_chat_t* chat); +/** + * Checks if the chat was protected, and then an incoming message broke this protection. + * + * This function is only useful if the UI enabled the `verified_one_on_one_chats` feature flag, + * otherwise it will return false for all chats. + * + * 1:1 chats are automatically set as protected when a contact is verified. + * When a message comes in that is not encrypted / signed correctly, + * the chat is automatically set as unprotected again. + * dc_chat_is_protection_broken() will return true until dc_accept_chat() is called. + * + * The UI should let the user confirm that this is OK with a message like + * `Bob sent a message from another device. Tap to learn more` and then call dc_accept_chat(). + * @memberof dc_chat_t + * @param chat The chat object. + * @return 1=chat protection broken, 0=otherwise. + */ +int dc_chat_is_protection_broken (const dc_chat_t* chat); + + /** * Check if locations are sent to the chat * at the time the object was created using dc_get_chat(). @@ -4315,7 +4323,7 @@ int dc_msg_is_forwarded (const dc_msg_t* msg); * Check if the message is an informational message, created by the * device or by another users. Such messages are not "typed" by the user but * created due to other actions, - * e.g. dc_set_chat_name(), dc_set_chat_profile_image(), dc_set_chat_protection() + * e.g. dc_set_chat_name(), dc_set_chat_profile_image(), * or dc_add_contact_to_chat(). * * These messages are typically shown in the center of the chat view, @@ -6749,15 +6757,6 @@ void dc_event_unref(dc_event_t* event); /// Used in error strings. #define DC_STR_ERROR_NO_NETWORK 87 -/// "Chat protection enabled." -/// - -/// @deprecated Deprecated, replaced by DC_STR_MSG_YOU_ENABLED_PROTECTION and DC_STR_MSG_PROTECTION_ENABLED_BY. -#define DC_STR_PROTECTION_ENABLED 88 - -/// @deprecated Deprecated, replaced by DC_STR_MSG_YOU_DISABLED_PROTECTION and DC_STR_MSG_PROTECTION_DISABLED_BY. -#define DC_STR_PROTECTION_DISABLED 89 - /// "Reply" /// /// Used in summaries. @@ -7202,26 +7201,6 @@ void dc_event_unref(dc_event_t* event); /// `%2$s` will be replaced by name and address of the contact. #define DC_STR_EPHEMERAL_TIMER_WEEKS_BY_OTHER 157 -/// "You enabled chat protection." -/// -/// Used in status messages. -#define DC_STR_PROTECTION_ENABLED_BY_YOU 158 - -/// "Chat protection enabled by %1$s." -/// -/// `%1$s` will be replaced by name and address of the contact. -/// -/// Used in status messages. -#define DC_STR_PROTECTION_ENABLED_BY_OTHER 159 - -/// "You disabled chat protection." -#define DC_STR_PROTECTION_DISABLED_BY_YOU 160 - -/// "Chat protection disabled by %1$s." -/// -/// `%1$s` will be replaced by name and address of the contact. -#define DC_STR_PROTECTION_DISABLED_BY_OTHER 161 - /// "Scan to set up second device for %1$s" /// /// `%1$s` will be replaced by name and address of the account. @@ -7232,6 +7211,16 @@ void dc_event_unref(dc_event_t* event); /// Used as a device message after a successful backup transfer. #define DC_STR_BACKUP_TRANSFER_MSG_BODY 163 +/// "Messages are guaranteed to be end-to-end encrypted from now on." +/// +/// Used in info messages. +#define DC_STR_CHAT_PROTECTION_ENABLED 170 + +/// "%1$s sent a message from another device." +/// +/// Used in info messages. +#define DC_STR_CHAT_PROTECTION_DISABLED 171 + /** * @} */ diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index f6c4c7e9f..b97a12d5a 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -1429,32 +1429,6 @@ pub unsafe extern "C" fn dc_get_next_media( }) } -#[no_mangle] -pub unsafe extern "C" fn dc_set_chat_protection( - context: *mut dc_context_t, - chat_id: u32, - protect: libc::c_int, -) -> libc::c_int { - if context.is_null() { - eprintln!("ignoring careless call to dc_set_chat_protection()"); - return 0; - } - let ctx = &*context; - let protect = if let Some(s) = ProtectionStatus::from_i32(protect) { - s - } else { - warn!(ctx, "bad protect-value for dc_set_chat_protection()"); - return 0; - }; - - block_on(async move { - match ChatId::new(chat_id).set_protection(ctx, protect).await { - Ok(()) => 1, - Err(_) => 0, - } - }) -} - #[no_mangle] pub unsafe extern "C" fn dc_set_chat_visibility( context: *mut dc_context_t, @@ -3084,6 +3058,16 @@ pub unsafe extern "C" fn dc_chat_is_protected(chat: *mut dc_chat_t) -> libc::c_i ffi_chat.chat.is_protected() as libc::c_int } +#[no_mangle] +pub unsafe extern "C" fn dc_chat_is_protection_broken(chat: *mut dc_chat_t) -> libc::c_int { + if chat.is_null() { + eprintln!("ignoring careless call to dc_chat_is_protection_broken()"); + return 0; + } + let ffi_chat = &*chat; + ffi_chat.chat.is_protection_broken() as libc::c_int +} + #[no_mangle] pub unsafe extern "C" fn dc_chat_is_sending_locations(chat: *mut dc_chat_t) -> libc::c_int { if chat.is_null() { diff --git a/deltachat-repl/src/cmdline.rs b/deltachat-repl/src/cmdline.rs index c3e473dbe..7bb4c40bc 100644 --- a/deltachat-repl/src/cmdline.rs +++ b/deltachat-repl/src/cmdline.rs @@ -18,6 +18,7 @@ use deltachat::imex::*; use deltachat::location; use deltachat::log::LogExt; use deltachat::message::{self, Message, MessageState, MsgId, Viewtype}; +use deltachat::mimeparser::SystemMessage; use deltachat::peerstate::*; use deltachat::qr::*; use deltachat::reaction::send_reaction; @@ -210,7 +211,17 @@ async fn log_msg(context: &Context, prefix: impl AsRef, msg: &Message) { } else { "[FRESH]" }, - if msg.is_info() { "[INFO]" } else { "" }, + if msg.is_info() { + if msg.get_info_type() == SystemMessage::ChatProtectionEnabled { + "[INFO 🛡️]" + } else if msg.get_info_type() == SystemMessage::ChatProtectionDisabled { + "[INFO 🛡️❌]" + } else { + "[INFO]" + } + } else { + "" + }, if msg.get_viewtype() == Viewtype::VideochatInvitation { format!( "[VIDEOCHAT-INVITATION: {}, type={}]", @@ -395,8 +406,6 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu unpin \n\ mute []\n\ unmute \n\ - protect \n\ - unprotect \n\ delchat \n\ accept \n\ decline \n\ @@ -1056,20 +1065,6 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu }; chat::set_muted(&context, chat_id, duration).await?; } - "protect" | "unprotect" => { - ensure!(!arg1.is_empty(), "Argument missing."); - let chat_id = ChatId::new(arg1.parse()?); - chat_id - .set_protection( - &context, - match arg0 { - "protect" => ProtectionStatus::Protected, - "unprotect" => ProtectionStatus::Unprotected, - _ => unreachable!("arg0={:?}", arg0), - }, - ) - .await?; - } "delchat" => { ensure!(!arg1.is_empty(), "Argument missing."); let chat_id = ChatId::new(arg1.parse()?); diff --git a/node/lib/context.ts b/node/lib/context.ts index 4c926ba78..a219881a1 100644 --- a/node/lib/context.ts +++ b/node/lib/context.ts @@ -699,23 +699,6 @@ export class Context extends EventEmitter { ) } - /** - * - * @param chatId - * @param protect - * @returns success boolean - */ - setChatProtection(chatId: number, protect: boolean) { - debug(`setChatProtection ${chatId} ${protect}`) - return Boolean( - binding.dcn_set_chat_protection( - this.dcn_context, - Number(chatId), - protect ? 1 : 0 - ) - ) - } - getChatEphemeralTimer(chatId: number): number { debug(`getChatEphemeralTimer ${chatId}`) return binding.dcn_get_chat_ephemeral_timer( diff --git a/node/src/module.c b/node/src/module.c index 3d3045017..de24e2c90 100644 --- a/node/src/module.c +++ b/node/src/module.c @@ -1399,18 +1399,6 @@ NAPI_METHOD(dcn_set_chat_name) { NAPI_RETURN_INT32(result); } -NAPI_METHOD(dcn_set_chat_protection) { - NAPI_ARGV(3); - NAPI_DCN_CONTEXT(); - NAPI_ARGV_UINT32(chat_id, 1); - NAPI_ARGV_INT32(protect, 1); - - int result = dc_set_chat_protection(dcn_context->dc_context, - chat_id, - protect); - NAPI_RETURN_INT32(result); -} - NAPI_METHOD(dcn_get_chat_ephemeral_timer) { NAPI_ARGV(2); NAPI_DCN_CONTEXT(); @@ -3491,7 +3479,6 @@ NAPI_INIT() { NAPI_EXPORT_FUNCTION(dcn_send_msg); NAPI_EXPORT_FUNCTION(dcn_send_videochat_invitation); NAPI_EXPORT_FUNCTION(dcn_set_chat_name); - NAPI_EXPORT_FUNCTION(dcn_set_chat_protection); NAPI_EXPORT_FUNCTION(dcn_get_chat_ephemeral_timer); NAPI_EXPORT_FUNCTION(dcn_set_chat_ephemeral_timer); NAPI_EXPORT_FUNCTION(dcn_set_chat_profile_image); diff --git a/src/chat.rs b/src/chat.rs index 950eb9e90..cc34d79ab 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -86,6 +86,14 @@ pub enum ProtectionStatus { /// /// All members of the chat must be verified. Protected = 1, + + /// The chat was protected, but now a new message came in + /// which was not encrypted / signed correctly. + /// The user has to confirm that this is OK. + /// + /// We only do this in 1:1 chats; in group chats, the chat just + /// stays protected. + ProtectionBroken = 3, // `2` was never used as a value. } /// The reason why messages cannot be sent to the chat. @@ -102,6 +110,10 @@ pub(crate) enum CantSendReason { /// The chat is a contact request, it needs to be accepted before sending a message. ContactRequest, + /// The chat was protected, but now a new message came in + /// which was not encrypted / signed correctly. + ProtectionBroken, + /// Mailing list without known List-Post header. ReadOnlyMailingList, @@ -118,6 +130,10 @@ impl fmt::Display for CantSendReason { f, "contact request chat should be accepted before sending messages" ), + Self::ProtectionBroken => write!( + f, + "accept that the encryption isn't verified anymore before sending messages" + ), Self::ReadOnlyMailingList => { write!(f, "mailing list does not have a know post address") } @@ -270,6 +286,7 @@ impl ChatId { param: Option, ) -> Result { let grpname = strip_rtlo_characters(grpname); + let smeared_time = create_smeared_timestamp(context); let row_id = context.sql.insert( "INSERT INTO chats (type, name, grpid, blocked, created_timestamp, protected, param) VALUES(?, ?, ?, ?, ?, ?, ?);", @@ -278,13 +295,20 @@ impl ChatId { &grpname, grpid, create_blocked, - create_smeared_timestamp(context), + smeared_time, create_protected, param.unwrap_or_default(), ), ).await?; let chat_id = ChatId::new(u32::try_from(row_id)?); + + if create_protected == ProtectionStatus::Protected { + chat_id + .add_protection_msg(context, ProtectionStatus::Protected, None, smeared_time) + .await?; + } + info!( context, "Created group/mailinglist '{}' grpid={} as {}, blocked={}.", @@ -374,6 +398,13 @@ impl ChatId { match chat.typ { Chattype::Undefined => bail!("Can't accept chat of undefined chattype"), + Chattype::Single if chat.protected == ProtectionStatus::ProtectionBroken => { + // The chat was in the 'Request' state because the protection was broken. + // The user clicked 'Accept', so, now we want to set the status to Unprotected again: + chat.id + .inner_set_protection(context, ProtectionStatus::Unprotected) + .await?; + } Chattype::Single | Chattype::Group | Chattype::Broadcast => { // User has "created a chat" with all these contacts. // @@ -400,20 +431,19 @@ impl ChatId { /// Sets protection without sending a message. /// - /// Used when a message arrives indicating that someone else has - /// changed the protection value for a chat. + /// Returns whether the protection status was actually modified. pub(crate) async fn inner_set_protection( self, context: &Context, protect: ProtectionStatus, - ) -> Result<()> { - ensure!(!self.is_special(), "Invalid chat-id."); + ) -> Result { + ensure!(!self.is_special(), "Invalid chat-id {self}."); let chat = Chat::load_from_db(context, self).await?; if protect == chat.protected { info!(context, "Protection status unchanged for {}.", self); - return Ok(()); + return Ok(false); } match protect { @@ -430,7 +460,7 @@ impl ChatId { Chattype::Mailinglist => bail!("Cannot protect mailing lists"), Chattype::Undefined => bail!("Undefined group type"), }, - ProtectionStatus::Unprotected => {} + ProtectionStatus::Unprotected | ProtectionStatus::ProtectionBroken => {} }; context @@ -443,68 +473,58 @@ impl ChatId { // make sure, the receivers will get all keys self.reset_gossiped_timestamp(context).await?; - Ok(()) + Ok(true) } - /// Send protected status message to the chat. + /// Adds an info message to the chat, telling the user that the protection status changed. /// - /// This sends the message with the protected status change to the chat, - /// notifying the user on this device as well as the other users in the chat. + /// Params: /// - /// If `promote` is false this means, the message must not be sent out - /// and only a local info message should be added to the chat. - /// This is used when protection is enabled implicitly or when a chat is not yet promoted. + /// * `contact_id`: In a 1:1 chat, pass the chat partner's contact id. + /// * `timestamp_sort` is used as the timestamp of the added message + /// and should be the timestamp of the change happening. pub(crate) async fn add_protection_msg( self, context: &Context, protect: ProtectionStatus, - promote: bool, - from_id: ContactId, + contact_id: Option, + timestamp_sort: i64, ) -> Result<()> { - let text = context.stock_protection_msg(protect, from_id).await; + let text = context.stock_protection_msg(protect, contact_id).await; let cmd = match protect { ProtectionStatus::Protected => SystemMessage::ChatProtectionEnabled, ProtectionStatus::Unprotected => SystemMessage::ChatProtectionDisabled, + ProtectionStatus::ProtectionBroken => SystemMessage::ChatProtectionDisabled, }; - - if promote { - let mut msg = Message { - viewtype: Viewtype::Text, - text, - ..Default::default() - }; - msg.param.set_cmd(cmd); - send_msg(context, self, &mut msg).await?; - } else { - add_info_msg_with_cmd( - context, - self, - &text, - cmd, - create_smeared_timestamp(context), - None, - None, - None, - ) - .await?; - } + add_info_msg_with_cmd(context, self, &text, cmd, timestamp_sort, None, None, None).await?; Ok(()) } /// Sets protection and sends or adds a message. - pub async fn set_protection(self, context: &Context, protect: ProtectionStatus) -> Result<()> { - ensure!(!self.is_special(), "set protection: invalid chat-id."); - - let chat = Chat::load_from_db(context, self).await?; - - if let Err(e) = self.inner_set_protection(context, protect).await { - error!(context, "Cannot set protection: {e:#}."); // make error user-visible - return Err(e); + /// + /// `timestamp_sort` is used as the timestamp of the added message + /// and should be the timestamp of the change happening. + pub(crate) async fn set_protection( + self, + context: &Context, + protect: ProtectionStatus, + timestamp_sort: i64, + contact_id: Option, + ) -> Result<()> { + match self.inner_set_protection(context, protect).await { + Ok(protection_status_modified) => { + if protection_status_modified { + self.add_protection_msg(context, protect, contact_id, timestamp_sort) + .await?; + } + Ok(()) + } + Err(e) => { + error!(context, "Cannot set protection: {e:#}."); // make error user-visible + Err(e) + } } - - self.add_protection_msg(context, protect, chat.is_promoted(), ContactId::SELF) - .await } /// Archives or unarchives a chat. @@ -1141,7 +1161,7 @@ pub struct Chat { pub grpid: String, /// Whether the chat is blocked, unblocked or a contact request. - pub(crate) blocked: Blocked, + pub blocked: Blocked, /// Additional chat parameters stored in the database. pub param: Params, @@ -1153,7 +1173,7 @@ pub struct Chat { pub mute_duration: MuteDuration, /// If the chat is protected (verified). - protected: ProtectionStatus, + pub(crate) protected: ProtectionStatus, } impl Chat { @@ -1247,6 +1267,8 @@ impl Chat { Some(DeviceChat) } else if self.is_contact_request() { Some(ContactRequest) + } else if self.is_protection_broken() { + Some(ProtectionBroken) } else if self.is_mailing_list() && self.param.get(Param::ListPost).is_none_or_empty() { Some(ReadOnlyMailingList) } else if !self.is_self_in_chat(context).await? { @@ -1410,6 +1432,27 @@ impl Chat { self.protected == ProtectionStatus::Protected } + /// Returns true if the chat was protected, and then an incoming message broke this protection. + /// + /// This function is only useful if the UI enabled the `verified_one_on_one_chats` feature flag, + /// otherwise it will return false for all chats. + /// + /// 1:1 chats are automatically set as protected when a contact is verified. + /// When a message comes in that is not encrypted / signed correctly, + /// the chat is automatically set as unprotected again. + /// `is_protection_broken()` will return true until `chat_id.accept()` is called. + /// + /// The UI should let the user confirm that this is OK with a message like + /// `Bob sent a message from another device. Tap to learn more` + /// and then call `chat_id.accept()`. + pub fn is_protection_broken(&self) -> bool { + match self.protected { + ProtectionStatus::Protected => false, + ProtectionStatus::Unprotected => false, + ProtectionStatus::ProtectionBroken => true, + } + } + /// Returns true if location streaming is enabled in the chat. pub fn is_sending_locations(&self) -> bool { self.is_sending_locations @@ -1440,15 +1483,6 @@ impl Chat { let mut to_id = 0; let mut location_id = 0; - if let Some(reason) = self.why_cant_send(context).await? { - if self.typ == Chattype::Group && reason == CantSendReason::NotAMember { - context.emit_event(EventType::ErrorSelfNotInGroup( - "Cannot send message; self not in group.".into(), - )); - } - bail!("Cannot send message to {}: {}", self.id, reason); - } - let from = context.get_primary_self_addr().await?; let new_rfc724_mid = { let grpid = match self.typ { @@ -1964,19 +1998,28 @@ impl ChatIdBlocked { _ => (), } + let peerstate = Peerstate::from_addr(context, contact.get_addr()).await?; + let protected = peerstate.map_or(false, |p| p.is_using_verified_key()); + let smeared_time = create_smeared_timestamp(context); + let chat_id = context .sql .transaction(move |transaction| { transaction.execute( "INSERT INTO chats - (type, name, param, blocked, created_timestamp) - VALUES(?, ?, ?, ?, ?)", + (type, name, param, blocked, created_timestamp, protected) + VALUES(?, ?, ?, ?, ?, ?)", ( Chattype::Single, chat_name, params.to_string(), create_blocked as u8, - create_smeared_timestamp(context), + smeared_time, + if protected { + ProtectionStatus::Protected + } else { + ProtectionStatus::Unprotected + }, ), )?; let chat_id = ChatId::new( @@ -1997,6 +2040,17 @@ impl ChatIdBlocked { }) .await?; + if protected { + chat_id + .add_protection_msg( + context, + ProtectionStatus::Protected, + Some(contact_id), + smeared_time, + ) + .await?; + } + match contact_id { ContactId::SELF => update_saved_messages_icon(context).await?, ContactId::DEVICE => update_device_icon(context).await?, @@ -2100,7 +2154,13 @@ async fn prepare_msg_common( // Check if the chat can be sent to. if let Some(reason) = chat.why_cant_send(context).await? { - bail!("cannot send to {}: {}", chat_id, reason); + if reason == CantSendReason::ProtectionBroken + && msg.param.get_cmd() == SystemMessage::SecurejoinMessage + { + // Send out the message, the securejoin message is supposed to repair the verification + } else { + bail!("cannot send to {chat_id}: {reason}"); + } } // check current MessageState for drafts (to keep msg_id) ... @@ -2850,18 +2910,14 @@ pub async fn create_group_chat( let grpid = create_id(); + let timestamp = create_smeared_timestamp(context); let row_id = context .sql .insert( "INSERT INTO chats (type, name, grpid, param, created_timestamp) VALUES(?, ?, ?, \'U=1\', ?);", - ( - Chattype::Group, - chat_name, - grpid, - create_smeared_timestamp(context), - ), + (Chattype::Group, chat_name, grpid, timestamp), ) .await?; @@ -2873,9 +2929,9 @@ pub async fn create_group_chat( context.emit_msgs_changed_without_ids(); if protect == ProtectionStatus::Protected { - // this part is to stay compatible to verified groups, - // in some future, we will drop the "protect"-flag from create_group_chat() - chat_id.inner_set_protection(context, protect).await?; + chat_id + .set_protection(context, protect, timestamp, None) + .await?; } Ok(chat_id) @@ -5131,72 +5187,6 @@ mod tests { Ok(()) } - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - async fn test_set_protection() -> Result<()> { - let t = TestContext::new_alice().await; - t.set_config_bool(Config::BccSelf, false).await?; - let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; - let chat = Chat::load_from_db(&t, chat_id).await?; - assert!(!chat.is_protected()); - assert!(chat.is_unpromoted()); - - // enable protection on unpromoted chat, the info-message is added via add_info_msg() - chat_id - .set_protection(&t, ProtectionStatus::Protected) - .await?; - - let chat = Chat::load_from_db(&t, chat_id).await?; - assert!(chat.is_protected()); - assert!(chat.is_unpromoted()); - - let msgs = get_chat_msgs(&t, chat_id).await?; - assert_eq!(msgs.len(), 1); - - let msg = t.get_last_msg_in(chat_id).await; - assert!(msg.is_info()); - assert_eq!(msg.get_info_type(), SystemMessage::ChatProtectionEnabled); - assert_eq!(msg.get_state(), MessageState::InNoticed); - - // disable protection again, still unpromoted - chat_id - .set_protection(&t, ProtectionStatus::Unprotected) - .await?; - - let chat = Chat::load_from_db(&t, chat_id).await?; - assert!(!chat.is_protected()); - assert!(chat.is_unpromoted()); - - let msg = t.get_last_msg_in(chat_id).await; - assert!(msg.is_info()); - assert_eq!(msg.get_info_type(), SystemMessage::ChatProtectionDisabled); - assert_eq!(msg.get_state(), MessageState::InNoticed); - - // send a message, this switches to promoted state - send_text_msg(&t, chat_id, "hi!".to_string()).await?; - - let chat = Chat::load_from_db(&t, chat_id).await?; - assert!(!chat.is_protected()); - assert!(!chat.is_unpromoted()); - - let msgs = get_chat_msgs(&t, chat_id).await?; - assert_eq!(msgs.len(), 3); - - // enable protection on promoted chat, the info-message is sent via send_msg() this time - chat_id - .set_protection(&t, ProtectionStatus::Protected) - .await?; - let chat = Chat::load_from_db(&t, chat_id).await?; - assert!(chat.is_protected()); - assert!(!chat.is_unpromoted()); - - let msg = t.get_last_msg_in(chat_id).await; - assert!(msg.is_info()); - assert_eq!(msg.get_info_type(), SystemMessage::ChatProtectionEnabled); - assert_eq!(msg.get_state(), MessageState::OutDelivered); // as bcc-self is disabled and there is nobody else in the chat - - Ok(()) - } - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_lookup_by_contact_id() { let ctx = TestContext::new_alice().await; diff --git a/src/config.rs b/src/config.rs index b90b444c3..2e243ba53 100644 --- a/src/config.rs +++ b/src/config.rs @@ -311,6 +311,16 @@ pub enum Config { /// Last message processed by the bot. LastMsgId, + + /// Feature flag for verified 1:1 chats; the UI should set it + /// to 1 if it supports verified 1:1 chats. + /// Regardless of this setting, `chat.is_protected()` returns true while the key is verified, + /// and when the key changes, an info message is posted into the chat. + /// 0=Nothing else happens when the key changes. + /// 1=After the key changed, `can_send()` returns false and `is_protection_broken()` returns true + /// until `chat_id.accept()` is called. + #[strum(props(default = "0"))] + VerifiedOneOnOneChats, } impl Context { diff --git a/src/context.rs b/src/context.rs index 270676031..8209f445f 100644 --- a/src/context.rs +++ b/src/context.rs @@ -755,6 +755,12 @@ impl Context { "last_msg_id", self.get_config_int(Config::LastMsgId).await?.to_string(), ); + res.insert( + "verified_one_on_one_chats", + self.get_config_bool(Config::VerifiedOneOnOneChats) + .await? + .to_string(), + ); let elapsed = self.creation_time.elapsed(); res.insert("uptime", duration_to_str(elapsed.unwrap_or_default())); diff --git a/src/lib.rs b/src/lib.rs index 28778eb19..b1230e2d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,6 @@ missing_debug_implementations, missing_docs, clippy::all, - clippy::indexing_slicing, clippy::wildcard_imports, clippy::needless_borrow, clippy::cast_lossless, @@ -17,6 +16,7 @@ clippy::explicit_into_iter_loop, clippy::cloned_instead_of_copied )] +#![cfg_attr(not(test), warn(clippy::indexing_slicing))] #![allow( clippy::match_bool, clippy::mixed_read_write_in_expression, diff --git a/src/mimefactory.rs b/src/mimefactory.rs index ce0dac303..4581958d2 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -896,7 +896,17 @@ impl<'a> MimeFactory<'a> { let mut placeholdertext = None; let mut meta_part = None; - if chat.is_protected() { + let send_verified_headers = match chat.typ { + Chattype::Undefined => bail!("Undefined chat type"), + // In single chats, the protection status isn't necessarily the same for both sides, + // so we don't send the Chat-Verified header: + Chattype::Single => false, + Chattype::Group => true, + // Mailinglists and broadcast lists can actually never be verified: + Chattype::Mailinglist => false, + Chattype::Broadcast => false, + }; + if chat.is_protected() && send_verified_headers { headers .protected .push(Header::new("Chat-Verified".to_string(), "1".to_string())); diff --git a/src/peerstate.rs b/src/peerstate.rs index 8a08a175d..cbe4227f5 100644 --- a/src/peerstate.rs +++ b/src/peerstate.rs @@ -392,6 +392,31 @@ impl Peerstate { } } + /// Returns a reference to the contact's public key fingerprint. + /// + /// Similar to [`Self::peek_key`], but returns the fingerprint instead of the key. + fn peek_key_fingerprint(&self, min_verified: PeerstateVerifiedStatus) -> Option<&Fingerprint> { + match min_verified { + PeerstateVerifiedStatus::BidirectVerified => self.verified_key_fingerprint.as_ref(), + PeerstateVerifiedStatus::Unverified => self + .public_key_fingerprint + .as_ref() + .or(self.gossip_key_fingerprint.as_ref()), + } + } + + /// Returns true if the key used for opportunistic encryption in the 1:1 chat + /// is the same as the verified key. + /// + /// Note that verified groups always use the verified key no matter if the + /// opportunistic key matches or not. + pub(crate) fn is_using_verified_key(&self) -> bool { + let verified = self.peek_key_fingerprint(PeerstateVerifiedStatus::BidirectVerified); + + verified.is_some() + && verified == self.peek_key_fingerprint(PeerstateVerifiedStatus::Unverified) + } + /// Set this peerstate to verified /// Make sure to call `self.save_to_db` to save these changes /// Params: diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 6db785650..c1d58a6d8 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -4,7 +4,7 @@ use std::cmp::min; use std::collections::HashSet; use std::convert::TryFrom; -use anyhow::{bail, ensure, Context as _, Result}; +use anyhow::{Context as _, Result}; use mailparse::{parse_mail, SingleInfo}; use num_traits::FromPrimitive; use once_cell::sync::Lazy; @@ -14,7 +14,7 @@ use crate::chat::{self, Chat, ChatId, ChatIdBlocked, ProtectionStatus}; use crate::config::Config; use crate::constants::{Blocked, Chattype, ShowEmails, DC_CHAT_ID_TRASH}; use crate::contact::{ - may_be_valid_addr, normalize_name, Contact, ContactAddress, ContactId, Origin, VerifiedStatus, + may_be_valid_addr, normalize_name, Contact, ContactAddress, ContactId, Origin, }; use crate::context::Context; use crate::debug_logging::maybe_set_logging_xdc_inner; @@ -593,12 +593,17 @@ async fn add_parts( // In lookup_chat_by_reply() and create_or_lookup_group(), it can happen that the message is put into a chat // but the From-address is not a member of this chat. - if let Some(chat_id) = chat_id { - if !chat::is_contact_in_chat(context, chat_id, from_id).await? { - let chat = Chat::load_from_db(context, chat_id).await?; + if let Some(group_chat_id) = chat_id { + if !chat::is_contact_in_chat(context, group_chat_id, from_id).await? { + let chat = Chat::load_from_db(context, group_chat_id).await?; if chat.is_protected() { - let s = stock_str::unknown_sender_for_chat(context).await; - mime_parser.repl_msg_by_error(&s); + if chat.typ == Chattype::Single { + // Just assign the message to the 1:1 chat with the actual sender instead. + chat_id = None; + } else { + let s = stock_str::unknown_sender_for_chat(context).await; + mime_parser.repl_msg_by_error(&s); + } } else { // In non-protected chats, just mark the sender as overridden. Therefore, the UI will prepend `~` // to the sender's name, indicating to the user that he/she is not part of the group. @@ -614,7 +619,7 @@ async fn add_parts( context, mime_parser, sent_timestamp, - chat_id, + group_chat_id, from_id, to_ids, ) @@ -717,6 +722,44 @@ async fn add_parts( ); } } + + // The next block checks if the message was sent with verified encryption + // and sets the protection of the 1:1 chat accordingly. + if is_partial_download.is_none() + && mime_parser.get_header(HeaderDef::SecureJoin).is_none() + && !is_mdn + { + let mut new_protection = match has_verified_encryption( + context, + mime_parser, + from_id, + to_ids, + Chattype::Single, + ) + .await? + { + VerifiedEncryption::Verified => ProtectionStatus::Protected, + VerifiedEncryption::NotVerified(_) => ProtectionStatus::Unprotected, + }; + + let chat = Chat::load_from_db(context, chat_id).await?; + + if chat.protected != new_protection { + if new_protection == ProtectionStatus::Unprotected + && context + .get_config_bool(Config::VerifiedOneOnOneChats) + .await? + { + new_protection = ProtectionStatus::ProtectionBroken; + } + + let sort_timestamp = + calc_sort_timestamp(context, sent_timestamp, chat_id, true).await?; + chat_id + .set_protection(context, new_protection, sort_timestamp, Some(from_id)) + .await?; + } + } } } @@ -983,42 +1026,14 @@ async fn add_parts( // if a chat is protected and the message is fully downloaded, check additional properties if !chat_id.is_special() && is_partial_download.is_none() { let chat = Chat::load_from_db(context, chat_id).await?; - let new_status = match mime_parser.is_system_message { - SystemMessage::ChatProtectionEnabled => Some(ProtectionStatus::Protected), - SystemMessage::ChatProtectionDisabled => Some(ProtectionStatus::Unprotected), - _ => None, - }; - if chat.is_protected() || new_status.is_some() { - if let Err(err) = check_verified_properties(context, mime_parser, from_id, to_ids).await + if chat.is_protected() { + if let VerifiedEncryption::NotVerified(err) = + has_verified_encryption(context, mime_parser, from_id, to_ids, chat.typ).await? { warn!(context, "Verification problem: {err:#}."); let s = format!("{err}. See 'Info' for more details"); mime_parser.repl_msg_by_error(&s); - } else { - // change chat protection only when verification check passes - if let Some(new_status) = new_status { - if chat_id - .update_timestamp( - context, - Param::ProtectionSettingsTimestamp, - sent_timestamp, - ) - .await? - { - if let Err(e) = chat_id.inner_set_protection(context, new_status).await { - chat::add_info_msg( - context, - chat_id, - &format!("Cannot set protection: {e}"), - sort_timestamp, - ) - .await?; - // do not return an error as this would result in retrying the message - } - } - better_msg = Some(context.stock_protection_msg(new_status, from_id).await); - } } } } @@ -1520,7 +1535,9 @@ async fn create_or_lookup_group( } let create_protected = if mime_parser.get_header(HeaderDef::ChatVerified).is_some() { - if let Err(err) = check_verified_properties(context, mime_parser, from_id, to_ids).await { + if let VerifiedEncryption::NotVerified(err) = + has_verified_encryption(context, mime_parser, from_id, to_ids, Chattype::Group).await? + { warn!(context, "Verification problem: {err:#}."); let s = format!("{err}. See 'Info' for more details"); mime_parser.repl_msg_by_error(&s); @@ -1768,20 +1785,6 @@ async fn apply_group_changes( } } - if mime_parser.get_header(HeaderDef::ChatVerified).is_some() { - if let Err(err) = check_verified_properties(context, mime_parser, from_id, to_ids).await { - warn!(context, "Verification problem: {err:#}."); - let s = format!("{err}. See 'Info' for more details"); - mime_parser.repl_msg_by_error(&s); - } - - if !chat.is_protected() { - chat_id - .inner_set_protection(context, ProtectionStatus::Protected) - .await?; - } - } - // Recreate the member list. if recreate_member_list { if !chat::is_contact_in_chat(context, chat_id, from_id).await? { @@ -2118,49 +2121,53 @@ async fn create_adhoc_group( Ok(Some(new_chat_id)) } -async fn check_verified_properties( +enum VerifiedEncryption { + Verified, + NotVerified(String), // The string contains the reason why it's not verified +} + +/// Checks whether the message is allowed to appear in a protected chat. +/// +/// This means that it is encrypted, signed with a verified key, +/// and if it's a group, all the recipients are verified. +async fn has_verified_encryption( context: &Context, mimeparser: &MimeMessage, from_id: ContactId, to_ids: &[ContactId], -) -> Result<()> { - let contact = Contact::get_by_id(context, from_id).await?; + chat_type: Chattype, +) -> Result { + use VerifiedEncryption::*; - ensure!(mimeparser.was_encrypted(), "This message is not encrypted"); - - if mimeparser.get_header(HeaderDef::ChatVerified).is_none() { - // we do not fail here currently, this would exclude (a) non-deltas - // and (b) deltas with different protection views across multiple devices. - // for group creation or protection enabled/disabled, however, Chat-Verified is respected. - warn!( - context, - "{} did not mark message as protected.", - contact.get_addr() - ); + if from_id == ContactId::SELF && chat_type == Chattype::Single { + // For outgoing emails in the 1:1 chat, we have an exception that + // they are allowed to be unencrypted: + // 1. They can't be an attack (they are outgoing, not incoming) + // 2. Probably the unencryptedness is just a temporary state, after all + // the user obviously still uses DC + // -> Showing info messages everytime would be a lot of noise + // 3. The info messages that are shown to the user ("Your chat partner + // likely reinstalled DC" or similar) would be wrong. + return Ok(Verified); } + if !mimeparser.was_encrypted() { + return Ok(NotVerified("This message is not encrypted".to_string())); + }; + // ensure, the contact is verified // and the message is signed with a verified key of the sender. // this check is skipped for SELF as there is no proper SELF-peerstate // and results in group-splits otherwise. if from_id != ContactId::SELF { - let peerstate = Peerstate::from_addr(context, contact.get_addr()).await?; + let Some(peerstate) = &mimeparser.decryption_info.peerstate else { + return Ok(NotVerified("No peerstate, the contact isn't verified".to_string())); + }; - if peerstate.is_none() - || contact.is_verified_ex(context, peerstate.as_ref()).await? - != VerifiedStatus::BidirectVerified - { - bail!( - "Sender of this message is not verified: {}", - contact.get_addr() - ); - } - - if let Some(peerstate) = peerstate { - ensure!( - peerstate.has_verified_key(&mimeparser.signatures), - "The message was sent with non-verified encryption" - ); + if !peerstate.has_verified_key(&mimeparser.signatures) { + return Ok(NotVerified( + "The message was sent with non-verified encryption".to_string(), + )); } } @@ -2172,7 +2179,7 @@ async fn check_verified_properties( .collect::>(); if to_ids.is_empty() { - return Ok(()); + return Ok(Verified); } let rows = context @@ -2196,10 +2203,12 @@ async fn check_verified_properties( ) .await?; + let contact = Contact::get_by_id(context, from_id).await?; + for (to_addr, mut is_verified) in rows { info!( context, - "check_verified_properties: {:?} self={:?}.", + "has_verified_encryption: {:?} self={:?}.", to_addr, context.is_self_addr(&to_addr).await ); @@ -2233,13 +2242,13 @@ async fn check_verified_properties( } } if !is_verified { - bail!( + return Ok(NotVerified(format!( "{} is not a member of this protected chat", - to_addr.to_string() - ); + to_addr + ))); } } - Ok(()) + Ok(Verified) } /// Returns the last message referenced from `References` header if it is in the database. diff --git a/src/securejoin.rs b/src/securejoin.rs index 5ffa387ed..ba4b9743c 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -6,7 +6,7 @@ use anyhow::{bail, Context as _, Error, Result}; use percent_encoding::{utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC}; use crate::aheader::EncryptPreference; -use crate::chat::{self, Chat, ChatId, ChatIdBlocked}; +use crate::chat::{self, Chat, ChatId, ChatIdBlocked, ProtectionStatus}; use crate::config::Config; use crate::constants::Blocked; use crate::contact::{Contact, ContactId, Origin, VerifiedStatus}; @@ -701,6 +701,14 @@ async fn secure_connection_established( let contact = Contact::get_by_id(context, contact_id).await?; let msg = stock_str::contact_verified(context, &contact).await; chat::add_info_msg(context, chat_id, &msg, time()).await?; + chat_id + .set_protection( + context, + ProtectionStatus::Protected, + time(), + Some(contact_id), + ) + .await?; context.emit_event(EventType::ChatModified(chat_id)); Ok(()) } @@ -783,6 +791,8 @@ mod tests { use crate::contact::VerifiedStatus; use crate::peerstate::Peerstate; use crate::receive_imf::receive_imf; + use crate::stock_str::chat_protection_enabled; + use crate::test_utils::get_chat_msg; use crate::test_utils::{TestContext, TestContextManager}; use crate::tools::EmailAddress; @@ -921,7 +931,7 @@ mod tests { // Check Alice got the verified message in her 1:1 chat. { let chat = alice.create_chat(&bob).await; - let msg_id = chat::get_chat_msgs(&alice.ctx, chat.get_id()) + let msg_ids: Vec<_> = chat::get_chat_msgs(&alice.ctx, chat.get_id()) .await .unwrap() .into_iter() @@ -929,11 +939,17 @@ mod tests { chat::ChatItem::Message { msg_id } => Some(msg_id), _ => None, }) - .max() - .expect("No messages in Alice's 1:1 chat"); - let msg = Message::load_from_db(&alice.ctx, msg_id).await.unwrap(); - assert!(msg.is_info()); - assert!(msg.get_text().contains("bob@example.net verified")); + .collect(); + assert_eq!(msg_ids.len(), 2); + + let msg0 = Message::load_from_db(&alice.ctx, msg_ids[0]).await.unwrap(); + assert!(msg0.is_info()); + assert!(msg0.get_text().contains("bob@example.net verified")); + + let msg1 = Message::load_from_db(&alice.ctx, msg_ids[1]).await.unwrap(); + assert!(msg1.is_info()); + let expected_text = chat_protection_enabled(&alice).await; + assert_eq!(msg1.get_text(), expected_text); } // Check Alice sent the right message to Bob. @@ -969,7 +985,7 @@ mod tests { // Check Bob got the verified message in his 1:1 chat. { let chat = bob.create_chat(&alice).await; - let msg_id = chat::get_chat_msgs(&bob.ctx, chat.get_id()) + let msg_ids: Vec<_> = chat::get_chat_msgs(&bob.ctx, chat.get_id()) .await .unwrap() .into_iter() @@ -977,11 +993,16 @@ mod tests { chat::ChatItem::Message { msg_id } => Some(msg_id), _ => None, }) - .max() - .expect("No messages in Bob's 1:1 chat"); - let msg = Message::load_from_db(&bob.ctx, msg_id).await.unwrap(); - assert!(msg.is_info()); - assert!(msg.get_text().contains("alice@example.org verified")); + .collect(); + + let msg0 = Message::load_from_db(&bob.ctx, msg_ids[0]).await.unwrap(); + assert!(msg0.is_info()); + assert!(msg0.get_text().contains("alice@example.org verified")); + + let msg1 = Message::load_from_db(&bob.ctx, msg_ids[1]).await.unwrap(); + assert!(msg1.is_info()); + let expected_text = chat_protection_enabled(&bob).await; + assert_eq!(msg1.get_text(), expected_text); } // Check Bob sent the final message @@ -1278,17 +1299,11 @@ mod tests { Blocked::Yes, "Alice's 1:1 chat with Bob is not hidden" ); - let msg_id = chat::get_chat_msgs(&alice.ctx, alice_chatid) - .await - .unwrap() - .into_iter() - .filter_map(|item| match item { - chat::ChatItem::Message { msg_id } => Some(msg_id), - _ => None, - }) - .min() - .expect("No messages in Alice's group chat"); - let msg = Message::load_from_db(&alice.ctx, msg_id).await.unwrap(); + // There should be 3 messages in the chat: + // - The ChatProtectionEnabled message + // - bob@example.net verified + // - You added member bob@example.net + let msg = get_chat_msg(&alice, alice_chatid, 1, 3).await; assert!(msg.is_info()); assert!(msg.get_text().contains("bob@example.net verified")); } diff --git a/src/securejoin/bob.rs b/src/securejoin/bob.rs index 674fa94f7..c824a5367 100644 --- a/src/securejoin/bob.rs +++ b/src/securejoin/bob.rs @@ -222,6 +222,14 @@ impl BobState { let msg = stock_str::contact_verified(context, &contact).await; let chat_id = self.joining_chat_id(context).await?; chat::add_info_msg(context, chat_id, &msg, time()).await?; + chat_id + .set_protection( + context, + ProtectionStatus::Protected, + time(), + Some(contact.id), + ) + .await?; context.emit_event(EventType::ChatModified(chat_id)); Ok(()) } diff --git a/src/stock_str.rs b/src/stock_str.rs index ea19a2a72..e4d43701b 100644 --- a/src/stock_str.rs +++ b/src/stock_str.rs @@ -393,18 +393,6 @@ pub enum StockMessage { #[strum(props(fallback = "Message deletion timer is set to %1$s weeks by %2$s."))] MsgEphemeralTimerWeeksBy = 157, - #[strum(props(fallback = "You enabled chat protection."))] - YouEnabledProtection = 158, - - #[strum(props(fallback = "Chat protection enabled by %1$s."))] - ProtectionEnabledBy = 159, - - #[strum(props(fallback = "You disabled chat protection."))] - YouDisabledProtection = 160, - - #[strum(props(fallback = "Chat protection disabled by %1$s."))] - ProtectionDisabledBy = 161, - #[strum(props(fallback = "Scan to set up second device for %1$s"))] BackupTransferQr = 162, @@ -419,6 +407,12 @@ pub enum StockMessage { #[strum(props(fallback = "I left the group."))] MsgILeftGroup = 166, + + #[strum(props(fallback = "Messages are guaranteed to be end-to-end encrypted from now on."))] + ChatProtectionEnabled = 170, + + #[strum(props(fallback = "%1$s sent a message from another device."))] + ChatProtectionDisabled = 171, } impl StockMessage { @@ -515,13 +509,21 @@ trait StockStringMods: AsRef + Sized { } impl ContactId { - /// Get contact name for stock string. - async fn get_stock_name(self, context: &Context) -> String { + /// Get contact name and address for stock string, e.g. `Bob (bob@example.net)` + async fn get_stock_name_n_addr(self, context: &Context) -> String { Contact::get_by_id(context, self) .await .map(|contact| contact.get_name_n_addr()) .unwrap_or_else(|_| self.to_string()) } + + /// Get contact name, e.g. `Bob`, or `bob@exmple.net` if no name is set. + async fn get_stock_name(self, context: &Context) -> String { + Contact::get_by_id(context, self) + .await + .map(|contact| contact.get_display_name().to_string()) + .unwrap_or_else(|_| self.to_string()) + } } impl StockStringMods for String {} @@ -583,7 +585,7 @@ pub(crate) async fn msg_grp_name( .await .replace1(from_group) .replace2(to_group) - .replace3(&by_contact.get_stock_name(context).await) + .replace3(&by_contact.get_stock_name_n_addr(context).await) } } @@ -593,7 +595,7 @@ pub(crate) async fn msg_grp_img_changed(context: &Context, by_contact: ContactId } else { translated(context, StockMessage::MsgGrpImgChangedBy) .await - .replace1(&by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name_n_addr(context).await) } } @@ -640,7 +642,7 @@ pub(crate) async fn msg_add_member_local( translated(context, StockMessage::MsgAddMemberBy) .await .replace1(whom) - .replace2(&by_contact.get_stock_name(context).await) + .replace2(&by_contact.get_stock_name_n_addr(context).await) } } @@ -687,7 +689,7 @@ pub(crate) async fn msg_del_member_local( translated(context, StockMessage::MsgDelMemberBy) .await .replace1(whom) - .replace2(&by_contact.get_stock_name(context).await) + .replace2(&by_contact.get_stock_name_n_addr(context).await) } } @@ -703,7 +705,7 @@ pub(crate) async fn msg_group_left_local(context: &Context, by_contact: ContactI } else { translated(context, StockMessage::MsgGroupLeftBy) .await - .replace1(&by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name_n_addr(context).await) } } @@ -756,7 +758,7 @@ pub(crate) async fn msg_grp_img_deleted(context: &Context, by_contact: ContactId } else { translated(context, StockMessage::MsgGrpImgDeletedBy) .await - .replace1(&by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name_n_addr(context).await) } } @@ -782,13 +784,9 @@ pub(crate) async fn secure_join_started( /// Stock string: `%1$s replied, waiting for being added to the group…`. pub(crate) async fn secure_join_replies(context: &Context, contact_id: ContactId) -> String { - if let Ok(contact) = Contact::get_by_id(context, contact_id).await { - translated(context, StockMessage::SecureJoinReplies) - .await - .replace1(contact.get_display_name()) - } else { - format!("secure_join_replies: unknown contact {contact_id}") - } + translated(context, StockMessage::SecureJoinReplies) + .await + .replace1(&contact_id.get_stock_name(context).await) } /// Stock string: `Scan to chat with %1$s`. @@ -881,7 +879,7 @@ pub(crate) async fn msg_location_enabled_by(context: &Context, contact: ContactI } else { translated(context, StockMessage::MsgLocationEnabledBy) .await - .replace1(&contact.get_stock_name(context).await) + .replace1(&contact.get_stock_name_n_addr(context).await) } } @@ -950,7 +948,7 @@ pub(crate) async fn msg_ephemeral_timer_disabled( } else { translated(context, StockMessage::MsgEphemeralTimerDisabledBy) .await - .replace1(&by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name_n_addr(context).await) } } @@ -968,7 +966,7 @@ pub(crate) async fn msg_ephemeral_timer_enabled( translated(context, StockMessage::MsgEphemeralTimerEnabledBy) .await .replace1(timer) - .replace2(&by_contact.get_stock_name(context).await) + .replace2(&by_contact.get_stock_name_n_addr(context).await) } } @@ -979,7 +977,7 @@ pub(crate) async fn msg_ephemeral_timer_minute(context: &Context, by_contact: Co } else { translated(context, StockMessage::MsgEphemeralTimerMinuteBy) .await - .replace1(&by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name_n_addr(context).await) } } @@ -990,7 +988,7 @@ pub(crate) async fn msg_ephemeral_timer_hour(context: &Context, by_contact: Cont } else { translated(context, StockMessage::MsgEphemeralTimerHourBy) .await - .replace1(&by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name_n_addr(context).await) } } @@ -1001,7 +999,7 @@ pub(crate) async fn msg_ephemeral_timer_day(context: &Context, by_contact: Conta } else { translated(context, StockMessage::MsgEphemeralTimerDayBy) .await - .replace1(&by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name_n_addr(context).await) } } @@ -1012,7 +1010,7 @@ pub(crate) async fn msg_ephemeral_timer_week(context: &Context, by_contact: Cont } else { translated(context, StockMessage::MsgEphemeralTimerWeekBy) .await - .replace1(&by_contact.get_stock_name(context).await) + .replace1(&by_contact.get_stock_name_n_addr(context).await) } } @@ -1053,26 +1051,16 @@ pub(crate) async fn error_no_network(context: &Context) -> String { translated(context, StockMessage::ErrorNoNetwork).await } -/// Stock string: `Chat protection enabled.`. -pub(crate) async fn protection_enabled(context: &Context, by_contact: ContactId) -> String { - if by_contact == ContactId::SELF { - translated(context, StockMessage::YouEnabledProtection).await - } else { - translated(context, StockMessage::ProtectionEnabledBy) - .await - .replace1(&by_contact.get_stock_name(context).await) - } +/// Stock string: `Messages are guaranteed to be end-to-end encrypted from now on.` +pub(crate) async fn chat_protection_enabled(context: &Context) -> String { + translated(context, StockMessage::ChatProtectionEnabled).await } -/// Stock string: `Chat protection disabled.`. -pub(crate) async fn protection_disabled(context: &Context, by_contact: ContactId) -> String { - if by_contact == ContactId::SELF { - translated(context, StockMessage::YouDisabledProtection).await - } else { - translated(context, StockMessage::ProtectionDisabledBy) - .await - .replace1(&by_contact.get_stock_name(context).await) - } +/// Stock string: `%1$s sent a message from another device.` +pub(crate) async fn chat_protection_disabled(context: &Context, contact_id: ContactId) -> String { + translated(context, StockMessage::ChatProtectionDisabled) + .await + .replace1(&contact_id.get_stock_name(context).await) } /// Stock string: `Reply`. @@ -1104,7 +1092,7 @@ pub(crate) async fn msg_ephemeral_timer_minutes( translated(context, StockMessage::MsgEphemeralTimerMinutesBy) .await .replace1(minutes) - .replace2(&by_contact.get_stock_name(context).await) + .replace2(&by_contact.get_stock_name_n_addr(context).await) } } @@ -1122,7 +1110,7 @@ pub(crate) async fn msg_ephemeral_timer_hours( translated(context, StockMessage::MsgEphemeralTimerHoursBy) .await .replace1(hours) - .replace2(&by_contact.get_stock_name(context).await) + .replace2(&by_contact.get_stock_name_n_addr(context).await) } } @@ -1140,7 +1128,7 @@ pub(crate) async fn msg_ephemeral_timer_days( translated(context, StockMessage::MsgEphemeralTimerDaysBy) .await .replace1(days) - .replace2(&by_contact.get_stock_name(context).await) + .replace2(&by_contact.get_stock_name_n_addr(context).await) } } @@ -1158,7 +1146,7 @@ pub(crate) async fn msg_ephemeral_timer_weeks( translated(context, StockMessage::MsgEphemeralTimerWeeksBy) .await .replace1(weeks) - .replace2(&by_contact.get_stock_name(context).await) + .replace2(&by_contact.get_stock_name_n_addr(context).await) } } @@ -1332,11 +1320,19 @@ impl Context { pub(crate) async fn stock_protection_msg( &self, protect: ProtectionStatus, - from_id: ContactId, + contact_id: Option, ) -> String { match protect { - ProtectionStatus::Unprotected => protection_enabled(self, from_id).await, - ProtectionStatus::Protected => protection_disabled(self, from_id).await, + ProtectionStatus::Unprotected | ProtectionStatus::ProtectionBroken => { + if let Some(contact_id) = contact_id { + chat_protection_disabled(self, contact_id).await + } else { + // In a group chat, it's not possible to downgrade verification. + // In a 1:1 chat, the `contact_id` always has to be provided. + "[Error] No contact_id given".to_string() + } + } + ProtectionStatus::Protected => chat_protection_enabled(self).await, } } diff --git a/src/test_utils.rs b/src/test_utils.rs index 52c4dd111..060256b0c 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -31,11 +31,14 @@ use crate::constants::Chattype; use crate::constants::{DC_GCL_NO_SPECIALS, DC_MSG_ID_DAYMARKER}; use crate::contact::{Contact, ContactAddress, ContactId, Modifier, Origin}; use crate::context::Context; +use crate::e2ee::EncryptHelper; use crate::events::{Event, EventType, Events}; use crate::key::{self, DcKey, KeyPair, KeyPairUse}; use crate::message::{update_msg_state, Message, MessageState, MsgId, Viewtype}; -use crate::mimeparser::MimeMessage; +use crate::mimeparser::{MimeMessage, SystemMessage}; +use crate::peerstate::Peerstate; use crate::receive_imf::receive_imf; +use crate::securejoin::{get_securejoin_qr, join_securejoin}; use crate::stock_str::StockStrings; use crate::tools::EmailAddress; @@ -108,9 +111,15 @@ impl TestContextManager { /// - Let one TestContext send a message /// - Let the other TestContext receive it and accept the chat /// - Assert that the message arrived - pub async fn send_recv_accept(&self, from: &TestContext, to: &TestContext, msg: &str) { + pub async fn send_recv_accept( + &self, + from: &TestContext, + to: &TestContext, + msg: &str, + ) -> Message { let received_msg = self.send_recv(from, to, msg).await; received_msg.chat_id.accept(to).await.unwrap(); + received_msg } /// - Let one TestContext send a message @@ -152,6 +161,27 @@ impl TestContextManager { new_addr ); } + + pub async fn execute_securejoin(&self, scanner: &TestContext, scanned: &TestContext) { + self.section(&format!( + "{} scans {}'s QR code", + scanner.name(), + scanned.name() + )); + + let qr = get_securejoin_qr(&scanned.ctx, None).await.unwrap(); + join_securejoin(&scanner.ctx, &qr).await.unwrap(); + + loop { + if let Some(sent) = scanner.pop_sent_msg_opt(Duration::ZERO).await { + scanned.recv_msg(&sent).await; + } else if let Some(sent) = scanned.pop_sent_msg_opt(Duration::ZERO).await { + scanner.recv_msg(&sent).await; + } else { + break; + } + } + } } #[derive(Debug, Clone, Default)] @@ -636,7 +666,7 @@ impl TestContext { // We're using `unwrap_or_default()` here so that if the file doesn't exist, // it can be created using `write` below. let expected = fs::read(&filename).await.unwrap_or_default(); - let expected = String::from_utf8(expected).unwrap(); + let expected = String::from_utf8(expected).unwrap().replace("\r\n", "\n"); if (std::env::var("UPDATE_GOLDEN_TESTS") == Ok("1".to_string())) && actual != expected { fs::write(&filename, &actual) .await @@ -1008,6 +1038,26 @@ fn print_logevent(logevent: &LogEvent) { } } +/// Saves the other account's public key as verified. +pub(crate) async fn mark_as_verified(this: &TestContext, other: &TestContext) { + let mut peerstate = Peerstate::from_header( + &EncryptHelper::new(other).await.unwrap().get_aheader(), + // We have to give 0 as the time, not the current time: + // The time is going to be saved in peerstate.last_seen. + // The code in `peerstate.rs` then compares `if message_time > self.last_seen`, + // and many similar checks in peerstate.rs, and doesn't allow changes otherwise. + // Giving the current time would mean that message_time == peerstate.last_seen, + // so changes would not be allowed. + // This might lead to flaky tests. + 0, + ); + + peerstate.verified_key = peerstate.public_key.clone(); + peerstate.verified_key_fingerprint = peerstate.public_key_fingerprint.clone(); + + peerstate.save_to_db(&this.sql).await.unwrap(); +} + /// Pretty-print an event to stdout /// /// Done during tests this is captured by `cargo test` and associated with the test itself. @@ -1114,7 +1164,17 @@ async fn write_msg(context: &Context, prefix: &str, msg: &Message, buf: &mut Str } else { "[FRESH]" }, - if msg.is_info() { "[INFO]" } else { "" }, + if msg.is_info() { + if msg.get_info_type() == SystemMessage::ChatProtectionEnabled { + "[INFO 🛡️]" + } else if msg.get_info_type() == SystemMessage::ChatProtectionDisabled { + "[INFO 🛡️❌]" + } else { + "[INFO]" + } + } else { + "" + }, if msg.get_viewtype() == Viewtype::VideochatInvitation { format!( "[VIDEOCHAT-INVITATION: {}, type={}]", diff --git a/src/tests.rs b/src/tests.rs index 9067f1962..3b417c0d4 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1 +1,2 @@ mod aeap; +mod verified_chats; diff --git a/src/tests/aeap.rs b/src/tests/aeap.rs index 0c43e8c17..f5f03ba83 100644 --- a/src/tests/aeap.rs +++ b/src/tests/aeap.rs @@ -8,10 +8,10 @@ use crate::contact; use crate::contact::Contact; use crate::contact::ContactId; use crate::message::Message; -use crate::peerstate; use crate::peerstate::Peerstate; use crate::receive_imf::receive_imf; use crate::stock_str; +use crate::test_utils::mark_as_verified; use crate::test_utils::TestContext; use crate::test_utils::TestContextManager; @@ -327,19 +327,6 @@ async fn check_no_transition_done(groups: &[ChatId], old_alice_addr: &str, bob: } } -async fn mark_as_verified(this: &TestContext, other: &TestContext) { - let other_addr = other.get_primary_self_addr().await.unwrap(); - let mut peerstate = peerstate::Peerstate::from_addr(this, &other_addr) - .await - .unwrap() - .unwrap(); - - peerstate.verified_key = peerstate.public_key.clone(); - peerstate.verified_key_fingerprint = peerstate.public_key_fingerprint.clone(); - - peerstate.save_to_db(&this.sql).await.unwrap(); -} - async fn get_last_info_msg(t: &TestContext, chat_id: ChatId) -> Option { let msgs = chat::get_chat_msgs_ex( &t.ctx, diff --git a/src/tests/verified_chats.rs b/src/tests/verified_chats.rs new file mode 100644 index 000000000..1967a320d --- /dev/null +++ b/src/tests/verified_chats.rs @@ -0,0 +1,508 @@ +use anyhow::Result; +use pretty_assertions::assert_eq; + +use crate::chat::{Chat, ProtectionStatus}; +use crate::config::Config; +use crate::contact::VerifiedStatus; +use crate::contact::{Contact, Origin}; +use crate::message::Message; +use crate::mimefactory::MimeFactory; +use crate::mimeparser::SystemMessage; +use crate::receive_imf::receive_imf; +use crate::stock_str; +use crate::test_utils::{get_chat_msg, mark_as_verified, TestContext, TestContextManager}; +use crate::{e2ee, message}; + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_verified_oneonone_chat_broken_by_classical() { + check_verified_oneonone_chat(true).await; +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_verified_oneonone_chat_broken_by_device_change() { + check_verified_oneonone_chat(false).await; +} + +async fn check_verified_oneonone_chat(broken_by_classical_email: bool) { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + enable_verified_oneonone_chats(&[&alice, &bob]).await; + + tcm.execute_securejoin(&alice, &bob).await; + + assert_verified(&alice, &bob, ProtectionStatus::Protected).await; + assert_verified(&bob, &alice, ProtectionStatus::Protected).await; + + if broken_by_classical_email { + tcm.section("Bob uses a classical MUA to send a message to Alice"); + receive_imf( + &alice, + b"Subject: Re: Message from alice\r\n\ + From: \r\n\ + To: \r\n\ + Date: Mon, 12 Dec 2022 14:33:39 +0000\r\n\ + Message-ID: \r\n\ + \r\n\ + Heyho!\r\n", + false, + ) + .await + .unwrap() + .unwrap(); + } else { + tcm.section("Bob sets up another Delta Chat device"); + let bob2 = TestContext::new().await; + enable_verified_oneonone_chats(&[&bob2]).await; + bob2.set_name("bob2"); + bob2.configure_addr("bob@example.net").await; + + tcm.send_recv(&bob2, &alice, "Using another device now") + .await; + } + + // Bob's contact is still verified, but the chat isn't marked as protected anymore + assert_verified(&alice, &bob, ProtectionStatus::ProtectionBroken).await; + + tcm.section("Bob sends another message from DC"); + tcm.send_recv(&bob, &alice, "Using DC again").await; + + let contact = alice.add_or_lookup_contact(&bob).await; + assert_eq!( + contact.is_verified(&alice.ctx).await.unwrap(), + VerifiedStatus::BidirectVerified + ); + + // Bob's chat is marked as verified again + assert_verified(&alice, &bob, ProtectionStatus::Protected).await; +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_create_verified_oneonone_chat() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + let fiona = tcm.fiona().await; + enable_verified_oneonone_chats(&[&alice, &bob, &fiona]).await; + + tcm.execute_securejoin(&alice, &bob).await; + tcm.execute_securejoin(&bob, &fiona).await; + assert_verified(&alice, &bob, ProtectionStatus::Protected).await; + assert_verified(&bob, &alice, ProtectionStatus::Protected).await; + assert_verified(&bob, &fiona, ProtectionStatus::Protected).await; + assert_verified(&fiona, &bob, ProtectionStatus::Protected).await; + + let group_id = bob + .create_group_with_members( + ProtectionStatus::Protected, + "Group with everyone", + &[&alice, &fiona], + ) + .await; + assert_eq!( + get_chat_msg(&bob, group_id, 0, 1).await.get_info_type(), + SystemMessage::ChatProtectionEnabled + ); + + { + let sent = bob.send_text(group_id, "Heyho").await; + alice.recv_msg(&sent).await; + + let msg = fiona.recv_msg(&sent).await; + assert_eq!( + get_chat_msg(&fiona, msg.chat_id, 0, 2) + .await + .get_info_type(), + SystemMessage::ChatProtectionEnabled + ); + } + + // Alice and Fiona should now be verified because of gossip + let alice_fiona_contact = alice.add_or_lookup_contact(&fiona).await; + assert_eq!( + alice_fiona_contact.is_verified(&alice).await.unwrap(), + VerifiedStatus::BidirectVerified + ); + + // As soon as Alice creates a chat with Fiona, it should directly be protected + { + let chat = alice.create_chat(&fiona).await; + assert!(chat.is_protected()); + + let msg = alice.get_last_msg().await; + let expected_text = stock_str::chat_protection_enabled(&alice).await; + assert_eq!(msg.text, expected_text); + } + + // Fiona should also see the chat as protected + { + let rcvd = tcm.send_recv(&alice, &fiona, "Hi Fiona").await; + let alice_fiona_id = rcvd.chat_id; + let chat = Chat::load_from_db(&fiona, alice_fiona_id).await?; + assert!(chat.is_protected()); + + let msg0 = get_chat_msg(&fiona, chat.id, 0, 2).await; + let expected_text = stock_str::chat_protection_enabled(&fiona).await; + assert_eq!(msg0.text, expected_text); + } + + tcm.section("Fiona reinstalls DC"); + drop(fiona); + + let fiona_new = tcm.unconfigured().await; + enable_verified_oneonone_chats(&[&fiona_new]).await; + fiona_new.configure_addr("fiona@example.net").await; + e2ee::ensure_secret_key_exists(&fiona_new).await?; + + tcm.send_recv(&fiona_new, &alice, "I have a new device") + .await; + + // The chat should be and stay unprotected + { + let chat = alice.get_chat(&fiona_new).await.unwrap(); + assert!(!chat.is_protected()); + assert!(chat.is_protection_broken()); + + // After recreating the chat, it should still be unprotected + chat.id.delete(&alice).await?; + + let chat = alice.create_chat(&fiona_new).await; + assert!(!chat.is_protected()); + assert!(!chat.is_protection_broken()); + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_create_unverified_oneonone_chat() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + enable_verified_oneonone_chats(&[&alice, &bob]).await; + + // A chat with an unknown contact should be created unprotected + let chat = alice.create_chat(&bob).await; + assert!(!chat.is_protected()); + assert!(!chat.is_protection_broken()); + + receive_imf( + &alice, + b"From: Bob \n\ + To: alice@example.org\n\ + Message-ID: <1234-2@example.org>\n\ + \n\ + hello\n", + false, + ) + .await?; + + chat.id.delete(&alice).await.unwrap(); + // Now Bob is a known contact, new chats should still be created unprotected + let chat = alice.create_chat(&bob).await; + assert!(!chat.is_protected()); + assert!(!chat.is_protection_broken()); + + tcm.send_recv(&bob, &alice, "hi").await; + chat.id.delete(&alice).await.unwrap(); + // Now we have a public key, new chats should still be created unprotected + let chat = alice.create_chat(&bob).await; + assert!(!chat.is_protected()); + assert!(!chat.is_protection_broken()); + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_degrade_verified_oneonone_chat() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + enable_verified_oneonone_chats(&[&alice, &bob]).await; + + mark_as_verified(&alice, &bob).await; + + let alice_chat = alice.create_chat(&bob).await; + assert!(alice_chat.is_protected()); + + receive_imf( + &alice, + b"From: Bob \n\ + To: alice@example.org\n\ + Message-ID: <1234-2@example.org>\n\ + \n\ + hello\n", + false, + ) + .await?; + + let contact_id = Contact::lookup_id_by_addr(&alice, "bob@example.net", Origin::Hidden) + .await? + .unwrap(); + + let msg0 = get_chat_msg(&alice, alice_chat.id, 0, 3).await; + let enabled = stock_str::chat_protection_enabled(&alice).await; + assert_eq!(msg0.text, enabled); + assert_eq!(msg0.param.get_cmd(), SystemMessage::ChatProtectionEnabled); + + let msg1 = get_chat_msg(&alice, alice_chat.id, 1, 3).await; + let disabled = stock_str::chat_protection_disabled(&alice, contact_id).await; + assert_eq!(msg1.text, disabled); + assert_eq!(msg1.param.get_cmd(), SystemMessage::ChatProtectionDisabled); + + let msg2 = get_chat_msg(&alice, alice_chat.id, 2, 3).await; + assert_eq!(msg2.text, "hello".to_string()); + assert!(!msg2.is_system_message()); + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_verified_oneonone_chat_enable_disable() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + enable_verified_oneonone_chats(&[&alice, &bob]).await; + + // Alice & Bob verify each other + mark_as_verified(&alice, &bob).await; + mark_as_verified(&bob, &alice).await; + + let chat = alice.create_chat(&bob).await; + assert!(chat.is_protected()); + + for alice_accepts_breakage in [true, false] { + // Bob uses Thunderbird to send a message + receive_imf( + &alice, + format!( + "From: Bob \n\ + To: alice@example.org\n\ + Message-ID: <1234-2{alice_accepts_breakage}@example.org>\n\ + \n\ + Message from Thunderbird\n" + ) + .as_bytes(), + false, + ) + .await?; + + let chat = alice.get_chat(&bob).await.unwrap(); + assert!(!chat.is_protected()); + assert!(chat.is_protection_broken()); + + if alice_accepts_breakage { + tcm.section("Alice clicks 'Accept' on the input-bar-dialog"); + chat.id.accept(&alice).await?; + let chat = alice.get_chat(&bob).await.unwrap(); + assert!(!chat.is_protected()); + assert!(!chat.is_protection_broken()); + } + + // Bob sends a message from DC again + tcm.send_recv(&bob, &alice, "Hello from DC").await; + let chat = alice.get_chat(&bob).await.unwrap(); + assert!(chat.is_protected()); + assert!(!chat.is_protection_broken()); + } + + alice + .golden_test_chat(chat.id, "test_verified_oneonone_chat_enable_disable") + .await; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_mdn_doesnt_disable_verification() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + enable_verified_oneonone_chats(&[&alice, &bob]).await; + bob.set_config_bool(Config::MdnsEnabled, true).await?; + + // Alice & Bob verify each other + mark_as_verified(&alice, &bob).await; + mark_as_verified(&bob, &alice).await; + + let rcvd = tcm.send_recv_accept(&alice, &bob, "Heyho").await; + message::markseen_msgs(&bob, vec![rcvd.id]).await?; + + let mimefactory = MimeFactory::from_mdn(&bob, &rcvd, vec![]).await?; + let rendered_msg = mimefactory.render(&bob).await?; + let body = rendered_msg.message; + receive_imf(&alice, body.as_bytes(), false).await.unwrap(); + + assert_verified(&alice, &bob, ProtectionStatus::Protected).await; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_outgoing_mua_msg() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + enable_verified_oneonone_chats(&[&alice, &bob]).await; + + mark_as_verified(&alice, &bob).await; + mark_as_verified(&bob, &alice).await; + + tcm.send_recv_accept(&bob, &alice, "Heyho from DC").await; + assert_verified(&alice, &bob, ProtectionStatus::Protected).await; + + let sent = receive_imf( + &alice, + b"From: alice@example.org\n\ + To: bob@example.net\n\ + \n\ + One classical MUA message", + false, + ) + .await? + .unwrap(); + tcm.send_recv_accept(&alice, &bob, "Sending with DC again") + .await; + + alice + .golden_test_chat(sent.chat_id, "test_outgoing_mua_msg") + .await; + + Ok(()) +} + +/// If Bob answers unencrypted from another address with a classical MUA, +/// the message is under some circumstances still assigned to the original +/// chat (see lookup_chat_by_reply()); this is meant to make aliases +/// work nicely. +/// However, if the original chat is verified, the unencrypted message +/// must NOT be assigned to it (it would be replaced by an error +/// message in the verified chat, so, this would just be a usability issue, +/// not a security issue). +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_reply() -> Result<()> { + for verified in [false, true] { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + enable_verified_oneonone_chats(&[&alice, &bob]).await; + + if verified { + mark_as_verified(&alice, &bob).await; + mark_as_verified(&bob, &alice).await; + } + + tcm.send_recv_accept(&bob, &alice, "Heyho from DC").await; + let encrypted_msg = tcm.send_recv_accept(&alice, &bob, "Heyho back").await; + + let unencrypted_msg = receive_imf( + &alice, + format!( + "From: bob@someotherdomain.org\n\ + To: some-alias-forwarding-to-alice@example.org\n\ + In-Reply-To: {}\n\ + \n\ + Weird reply", + encrypted_msg.rfc724_mid + ) + .as_bytes(), + false, + ) + .await? + .unwrap(); + + let unencrypted_msg = Message::load_from_db(&alice, unencrypted_msg.msg_ids[0]).await?; + assert_eq!(unencrypted_msg.text, "Weird reply"); + + if verified { + assert_ne!(unencrypted_msg.chat_id, encrypted_msg.chat_id); + } else { + assert_eq!(unencrypted_msg.chat_id, encrypted_msg.chat_id); + } + } + + Ok(()) +} + +/// Regression test for the following bug: +/// +/// - Scan your chat partner's QR Code +/// - They change devices +/// - They send you a message +/// - Without accepting the encryption downgrade, scan your chat partner's QR Code again +/// +/// -> The re-verification fails. +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_break_protection_then_verify_again() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + enable_verified_oneonone_chats(&[&alice, &bob]).await; + + // Cave: Bob can't write a message to Alice here. + // If he did, alice would increase his peerstate's last_seen timestamp. + // Then, after Bob reinstalls DC, alice's `if message_time > last_seen*` + // checks would return false (there are many checks of this form in peerstate.rs). + // Therefore, during the securejoin, Alice wouldn't accept the new key + // and reject the securejoin. + + mark_as_verified(&alice, &bob).await; + mark_as_verified(&bob, &alice).await; + + alice + .create_chat(&bob) + .await + .id + .inner_set_protection(&alice, ProtectionStatus::Protected) + .await?; + assert_verified(&alice, &bob, ProtectionStatus::Protected).await; + + tcm.section("Bob reinstalls DC"); + drop(bob); + let bob_new = tcm.unconfigured().await; + enable_verified_oneonone_chats(&[&bob_new]).await; + bob_new.configure_addr("bob@example.net").await; + e2ee::ensure_secret_key_exists(&bob_new).await?; + + tcm.send_recv(&bob_new, &alice, "I have a new device").await; + assert_verified(&alice, &bob_new, ProtectionStatus::ProtectionBroken).await; + assert!( + !alice + .get_chat(&bob_new) + .await + .unwrap() + .can_send(&alice) + .await? + ); + tcm.execute_securejoin(&alice, &bob_new).await; + assert_verified(&alice, &bob_new, ProtectionStatus::Protected).await; + + Ok(()) +} + +// ============== Helper Functions ============== + +async fn assert_verified(this: &TestContext, other: &TestContext, protected: ProtectionStatus) { + let contact = this.add_or_lookup_contact(other).await; + assert_eq!( + contact.is_verified(this).await.unwrap(), + VerifiedStatus::BidirectVerified + ); + + let chat = this.get_chat(other).await.unwrap(); + let (expect_protected, expect_broken) = match protected { + ProtectionStatus::Unprotected => (false, false), + ProtectionStatus::Protected => (true, false), + ProtectionStatus::ProtectionBroken => (false, true), + }; + assert_eq!(chat.is_protected(), expect_protected); + assert_eq!(chat.is_protection_broken(), expect_broken); +} + +async fn enable_verified_oneonone_chats(test_contexts: &[&TestContext]) { + for t in test_contexts { + t.set_config_bool(Config::VerifiedOneOnOneChats, true) + .await + .unwrap() + } +} diff --git a/test-data/golden/test_outgoing_mua_msg b/test-data/golden/test_outgoing_mua_msg new file mode 100644 index 000000000..549f84175 --- /dev/null +++ b/test-data/golden/test_outgoing_mua_msg @@ -0,0 +1,7 @@ +Single#Chat#10: bob@example.net [bob@example.net] 🛡️ +-------------------------------------------------------------------------------- +Msg#10: info (Contact#Contact#Info): Messages are guaranteed to be end-to-end encrypted from now on. [NOTICED][INFO 🛡️] +Msg#11🔒: (Contact#Contact#10): Heyho from DC [FRESH] +Msg#12: Me (Contact#Contact#Self): One classical MUA message √ +Msg#13🔒: Me (Contact#Contact#Self): Sending with DC again √ +-------------------------------------------------------------------------------- diff --git a/test-data/golden/test_verified_oneonone_chat_enable_disable b/test-data/golden/test_verified_oneonone_chat_enable_disable new file mode 100644 index 000000000..4da4a67d0 --- /dev/null +++ b/test-data/golden/test_verified_oneonone_chat_enable_disable @@ -0,0 +1,12 @@ +Single#Chat#10: Bob [bob@example.net] 🛡️ +-------------------------------------------------------------------------------- +Msg#10: info (Contact#Contact#Info): Messages are guaranteed to be end-to-end encrypted from now on. [NOTICED][INFO 🛡️] +Msg#11: info (Contact#Contact#Info): Bob sent a message from another device. [NOTICED][INFO 🛡️❌] +Msg#12: (Contact#Contact#10): Message from Thunderbird [FRESH] +Msg#13: info (Contact#Contact#Info): Messages are guaranteed to be end-to-end encrypted from now on. [NOTICED][INFO 🛡️] +Msg#14🔒: (Contact#Contact#10): Hello from DC [FRESH] +Msg#15: info (Contact#Contact#Info): Bob sent a message from another device. [NOTICED][INFO 🛡️❌] +Msg#16: (Contact#Contact#10): Message from Thunderbird [FRESH] +Msg#17: info (Contact#Contact#Info): Messages are guaranteed to be end-to-end encrypted from now on. [NOTICED][INFO 🛡️] +Msg#18🔒: (Contact#Contact#10): Hello from DC [FRESH] +-------------------------------------------------------------------------------- From d2b15cb6290a9909676781c3c4a1bfb96a995fe8 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 8 Jul 2023 19:49:12 +0000 Subject: [PATCH 003/102] docs: document how logs and error messages should be formatted --- CONTRIBUTING.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5bb9ea6f6..0285b2697 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -76,6 +76,29 @@ If you have multiple changes in one PR, create multiple conventional commits, an [Conventional Commits]: https://www.conventionalcommits.org/ [git-cliff]: https://git-cliff.org/ +### Errors + +Delta Chat core mostly uses [`anyhow`](https://docs.rs/anyhow/) errors. +When using [`Context`](https://docs.rs/anyhow/latest/anyhow/trait.Context.html), +capitalize it but do not add a full stop as the contexts will be separated by `:`. +For example: +``` +.with_context(|| format!("Unable to trash message {msg_id}")) +``` + +### Logging + +For logging, use `info!`, `warn!` and `error!` macros. +Log messages should be capitalized and have a full stop in the end. For example: +``` +info!(context, "Ignoring addition of {added_addr:?} to {chat_id}."); +``` + +Format anyhow errors with `{:#}` to print all the contexts like this: +``` +error!(context, "Failed to set selfavatar timestamp: {err:#}."); +``` + ### Reviewing Once a PR has an approval and passes CI, it can be merged. From 31e3169433eb9405b75ba4564517fd2690b76734 Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 10 Jul 2023 01:43:34 +0000 Subject: [PATCH 004/102] chore: nightly clippy fixes --- src/configure.rs | 6 +++--- src/configure/auto_mozilla.rs | 2 +- src/ephemeral.rs | 2 +- src/html.rs | 16 ++++++++-------- src/location.rs | 4 ++-- src/mimeparser.rs | 21 +++++++++++---------- src/plaintext.rs | 8 ++++---- src/provider.rs | 2 +- src/receive_imf.rs | 2 +- src/scheduler.rs | 2 +- src/smtp.rs | 10 +++++----- 11 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/configure.rs b/src/configure.rs index 42922f145..e82a49ff8 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -131,7 +131,7 @@ async fn on_configure_completed( ) -> Result<()> { if let Some(provider) = param.provider { if let Some(config_defaults) = &provider.config_defaults { - for def in config_defaults.iter() { + for def in config_defaults { if !context.config_exists(def.key).await? { info!(context, "apply config_defaults {}={}", def.key, def.value); context.set_config(def.key, Some(def.value)).await?; @@ -318,7 +318,7 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> { } // respect certificate setting from function parameters - for mut server in &mut servers { + for server in &mut servers { let certificate_checks = match server.protocol { Protocol::Imap => param.imap.certificate_checks, Protocol::Smtp => param.smtp.certificate_checks, @@ -653,7 +653,7 @@ async fn try_smtp_one_param( }) } else { info!(context, "success: {}", inf); - smtp.disconnect().await; + smtp.disconnect(); Ok(()) } } diff --git a/src/configure/auto_mozilla.rs b/src/configure/auto_mozilla.rs index 505691814..617429f59 100644 --- a/src/configure/auto_mozilla.rs +++ b/src/configure/auto_mozilla.rs @@ -234,7 +234,7 @@ fn parse_serverparams(in_emailaddr: &str, xml_raw: &str) -> Result Some(Protocol::Imap), diff --git a/src/ephemeral.rs b/src/ephemeral.rs index 5c5a64c17..54050a0e3 100644 --- a/src/ephemeral.rs +++ b/src/ephemeral.rs @@ -545,7 +545,7 @@ async fn next_expiration_timestamp(context: &Context) -> Option { ephemeral_timestamp .into_iter() - .chain(delete_device_after_timestamp.into_iter()) + .chain(delete_device_after_timestamp) .min() } diff --git a/src/html.rs b/src/html.rs index 306ce2ae1..7124c0a1a 100644 --- a/src/html.rs +++ b/src/html.rs @@ -291,7 +291,7 @@ mod tests { let parser = HtmlMsgParser::from_bytes(&t.ctx, raw).await.unwrap(); assert_eq!( parser.html, - r##" + r#" @@ -299,7 +299,7 @@ mod tests { This message does not have Content-Type nor Subject.

-"## +"# ); } @@ -310,7 +310,7 @@ This message does not have Content-Type nor Subject.
let parser = HtmlMsgParser::from_bytes(&t.ctx, raw).await.unwrap(); assert_eq!( parser.html, - r##" + r#" @@ -318,7 +318,7 @@ This message does not have Content-Type nor Subject.
message with a non-UTF-8 encoding: äöüßÄÖÜ

-"## +"# ); } @@ -330,7 +330,7 @@ message with a non-UTF-8 encoding: äöüßÄÖÜ
assert!(parser.plain.unwrap().flowed); assert_eq!( parser.html, - r##" + r#" @@ -341,7 +341,7 @@ This line does not end with a space
and will be wrapped as usual.

-"## +"# ); } @@ -352,7 +352,7 @@ and will be wrapped as usual.
let parser = HtmlMsgParser::from_bytes(&t.ctx, raw).await.unwrap(); assert_eq!( parser.html, - r##" + r#" @@ -363,7 +363,7 @@ test some special html-characters as < > and & but also " and &#x

-"## +"# ); } diff --git a/src/location.rs b/src/location.rs index 099ea3da9..7383dfc78 100644 --- a/src/location.rs +++ b/src/location.rs @@ -735,7 +735,7 @@ async fn maybe_send_locations(context: &Context) -> Result> { next_event = next_event .into_iter() - .chain(u64::try_from(locations_send_until - now).into_iter()) + .chain(u64::try_from(locations_send_until - now)) .min(); if has_locations { @@ -759,7 +759,7 @@ async fn maybe_send_locations(context: &Context) -> Result> { ); next_event = next_event .into_iter() - .chain(u64::try_from(locations_last_sent + 61 - now).into_iter()) + .chain(u64::try_from(locations_last_sent + 61 - now)) .min(); } } else { diff --git a/src/mimeparser.rs b/src/mimeparser.rs index a9a039685..a0cccd1b2 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -643,7 +643,7 @@ impl MimeMessage { .parts .iter_mut() .find(|part| !part.msg.is_empty() && !part.is_reaction); - if let Some(mut part) = part_with_text { + if let Some(part) = part_with_text { part.msg = format!("{} – {}", subject, part.msg); } } @@ -2062,7 +2062,8 @@ async fn handle_mdn( Ok((msg_id, chat_id, msg_state)) }, ) - .await? else { + .await? + else { info!( context, "Ignoring MDN, found no message with Message-ID {rfc724_mid:?} sent by us in the database.", @@ -3089,7 +3090,7 @@ CWt6wx7fiLp0qS9RrX75g6Gqw7nfCs6EcBERcIPt7DTe8VStJwf3LWqVwxl4gQl46yhfoqwEO+I= #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn parse_outlook_html_embedded_image() { let context = TestContext::new_alice().await; - let raw = br##"From: Anonymous + let raw = br#"From: Anonymous To: Anonymous Subject: Delta Chat is great stuff! Date: Tue, 5 May 2020 01:23:45 +0000 @@ -3144,7 +3145,7 @@ K+TuvC7qOah0WLFhcsXWn2+dDV1bXuAeC769TkqkpHhdXfUHnVgK3Pv7u3rVPT5AMeFUGxRB2dP4 CWt6wx7fiLp0qS9RrX75g6Gqw7nfCs6EcBERcIPt7DTe8VStJwf3LWqVwxl4gQl46yhfoqwEO+I= ------=_NextPart_000_0003_01D622B3.CA753E60-- -"##; +"#; let message = MimeMessage::from_bytes(&context.ctx, &raw[..], None) .await @@ -3519,7 +3520,7 @@ On 2020-10-25, Bob wrote: // A message with a long Message-ID. // Long message-IDs are generated by Mailjet. - let raw = br###"Date: Thu, 28 Jan 2021 00:26:57 +0000 + let raw = br"Date: Thu, 28 Jan 2021 00:26:57 +0000 Chat-Version: 1.0\n\ Message-ID: To: Bob @@ -3527,11 +3528,11 @@ From: Alice Subject: ... Some quote. -"###; +"; receive_imf(&t, raw, false).await?; // Delta Chat generates In-Reply-To with a starting tab when Message-ID is too long. - let raw = br###"In-Reply-To: + let raw = br"In-Reply-To: Date: Thu, 28 Jan 2021 00:26:57 +0000 Chat-Version: 1.0\n\ @@ -3543,7 +3544,7 @@ Subject: ... > Some quote. Some reply -"###; +"; receive_imf(&t, raw, false).await?; @@ -3561,7 +3562,7 @@ Some reply let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; - let raw = br###"Date: Thu, 28 Jan 2021 00:26:57 +0000 + let raw = br"Date: Thu, 28 Jan 2021 00:26:57 +0000 Chat-Version: 1.0\n\ Message-ID: To: Bob @@ -3570,7 +3571,7 @@ Subject: subject Chat-Disposition-Notification-To: alice@example.org Message. -"###; +"; // Bob receives message. receive_imf(&bob, raw, false).await?; diff --git a/src/plaintext.rs b/src/plaintext.rs index afd75b981..0c18fa104 100644 --- a/src/plaintext.rs +++ b/src/plaintext.rs @@ -26,10 +26,10 @@ impl PlainText { /// The function handles quotes, links, fixed and floating text paragraphs. pub fn to_html(&self) -> String { static LINKIFY_MAIL_RE: Lazy = - Lazy::new(|| regex::Regex::new(r#"\b([\w.\-+]+@[\w.\-]+)\b"#).unwrap()); + Lazy::new(|| regex::Regex::new(r"\b([\w.\-+]+@[\w.\-]+)\b").unwrap()); static LINKIFY_URL_RE: Lazy = Lazy::new(|| { - regex::Regex::new(r#"\b((http|https|ftp|ftps):[\w.,:;$/@!?&%\-~=#+]+)"#).unwrap() + regex::Regex::new(r"\b((http|https|ftp|ftps):[\w.,:;$/@!?&%\-~=#+]+)").unwrap() }); let lines = split_lines(&self.text); @@ -127,7 +127,7 @@ http://link-at-start-of-line.org .to_html(); assert_eq!( html, - r##" + r#" @@ -138,7 +138,7 @@ line with https://link-mid-of-line.orghttp://link-at-start-of-line.org

-"## +"# ); } diff --git a/src/provider.rs b/src/provider.rs index 58e1cd517..8035acd88 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -223,7 +223,7 @@ pub async fn get_provider_by_mx(context: &Context, domain: &str) -> Option<&'sta } if let Ok(mx_domains) = resolver.mx_lookup(fqdn).await { - for (provider_domain, provider) in PROVIDER_DATA.iter() { + for (provider_domain, provider) in &*PROVIDER_DATA { if provider.id != "gmail" { // MX lookup is limited to Gmail for security reasons continue; diff --git a/src/receive_imf.rs b/src/receive_imf.rs index c1d58a6d8..da2a89985 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -2347,7 +2347,7 @@ async fn add_or_lookup_contacts_by_address_list( origin: Origin, ) -> Result> { let mut contact_ids = HashSet::new(); - for info in address_list.iter() { + for info in address_list { let addr = &info.addr; if !may_be_valid_addr(addr) { continue; diff --git a/src/scheduler.rs b/src/scheduler.rs index 796222702..7ca697335 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -864,7 +864,7 @@ impl Scheduler { // Actually shutdown tasks. let timeout_duration = std::time::Duration::from_secs(30); - for b in once(self.inbox).chain(self.oboxes.into_iter()) { + for b in once(self.inbox).chain(self.oboxes) { tokio::time::timeout(timeout_duration, b.handle) .await .log_err(context) diff --git a/src/smtp.rs b/src/smtp.rs index 5cfc4fdfa..bea98ed48 100644 --- a/src/smtp.rs +++ b/src/smtp.rs @@ -55,7 +55,7 @@ impl Smtp { } /// Disconnect the SMTP transport and drop it entirely. - pub async fn disconnect(&mut self) { + pub fn disconnect(&mut self) { if let Some(mut transport) = self.transport.take() { // Closing connection with a QUIT command may take some time, especially if it's a // stale connection and an attempt to send the command times out. Send a command in a @@ -88,7 +88,7 @@ impl Smtp { pub async fn connect_configured(&mut self, context: &Context) -> Result<()> { if self.has_maybe_stale_connection() { info!(context, "Closing stale connection"); - self.disconnect().await; + self.disconnect(); } if self.is_connected() { @@ -465,13 +465,13 @@ pub(crate) async fn smtp_send( // this clears last_success info info!(context, "Failed to send message over SMTP, disconnecting"); - smtp.disconnect().await; + smtp.disconnect(); res } Err(crate::smtp::send::Error::Envelope(err)) => { // Local error, job is invalid, do not retry. - smtp.disconnect().await; + smtp.disconnect(); warn!(context, "SMTP job is invalid: {}", err); SendResult::Failure(err) } @@ -483,7 +483,7 @@ pub(crate) async fn smtp_send( } Err(crate::smtp::send::Error::Other(err)) => { // Local error, job is invalid, do not retry. - smtp.disconnect().await; + smtp.disconnect(); warn!(context, "unable to load job: {}", err); SendResult::Failure(err) } From 976797d4cf320bdb0e948112301b7bfb190e9356 Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 10 Jul 2023 18:52:39 +0000 Subject: [PATCH 005/102] build: remove examples/simple.rs When `cargo test` is executed, all examples are built by default to ensure that they can be compiled. This is a documented and expected behaviour, even though it was previously reported as a bug: In particular, `examples/simple.rs` is built into a 67M binary `target/debug/examples/simple`. This is unnecessary to do so every time you change a line in the `deltachat` crate and want to rerun the tests. Workaround is to run `cargo test --tests`, but it is easy to forget and is not discoverable unless you read the "Target Selection" section of `cargo help test`. We have a maintained example at https://github.com/deltachat-bot/echo, so there is no need for an example in the core repository. --- Cargo.toml | 5 --- examples/simple.rs | 100 --------------------------------------------- 2 files changed, 105 deletions(-) delete mode 100644 examples/simple.rs diff --git a/Cargo.toml b/Cargo.toml index 18fd4314f..012ad268f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -118,11 +118,6 @@ members = [ "format-flowed", ] -[[example]] -name = "simple" -path = "examples/simple.rs" - - [[bench]] name = "create_account" harness = false diff --git a/examples/simple.rs b/examples/simple.rs deleted file mode 100644 index cca50bb27..000000000 --- a/examples/simple.rs +++ /dev/null @@ -1,100 +0,0 @@ -use deltachat::chat::{self, ChatId}; -use deltachat::chatlist::*; -use deltachat::config; -use deltachat::contact::*; -use deltachat::context::*; -use deltachat::message::Message; -use deltachat::stock_str::StockStrings; -use deltachat::{EventType, Events}; -use tempfile::tempdir; - -fn cb(event: EventType) { - match event { - EventType::ConfigureProgress { progress, .. } => { - log::info!("progress: {}", progress); - } - EventType::Info(msg) => { - log::info!("{}", msg); - } - EventType::Warning(msg) => { - log::warn!("{}", msg); - } - EventType::Error(msg) => { - log::error!("{}", msg); - } - event => { - log::info!("{:?}", event); - } - } -} - -/// Run with `RUST_LOG=simple=info cargo run --release --example simple -- email pw`. -#[tokio::main] -async fn main() { - pretty_env_logger::try_init_timed().ok(); - - let dir = tempdir().unwrap(); - let dbfile = dir.path().join("db.sqlite"); - log::info!("creating database {:?}", dbfile); - let ctx = Context::new(&dbfile, 0, Events::new(), StockStrings::new()) - .await - .expect("Failed to create context"); - let info = ctx.get_info().await; - log::info!("info: {:#?}", info); - - let events = ctx.get_event_emitter(); - let events_spawn = tokio::task::spawn(async move { - while let Some(event) = events.recv().await { - cb(event.typ); - } - }); - - log::info!("configuring"); - let args = std::env::args().collect::>(); - assert_eq!(args.len(), 3, "requires email password"); - let email = args[1].clone(); - let pw = args[2].clone(); - ctx.set_config(config::Config::Addr, Some(&email)) - .await - .unwrap(); - ctx.set_config(config::Config::MailPw, Some(&pw)) - .await - .unwrap(); - - ctx.configure().await.unwrap(); - - log::info!("------ RUN ------"); - ctx.start_io().await; - log::info!("--- SENDING A MESSAGE ---"); - - let contact_id = Contact::create(&ctx, "dignifiedquire", "dignifiedquire@gmail.com") - .await - .unwrap(); - let chat_id = ChatId::create_for_contact(&ctx, contact_id).await.unwrap(); - - for i in 0..1 { - log::info!("sending message {}", i); - chat::send_text_msg(&ctx, chat_id, format!("Hi, here is my {i}nth message!")) - .await - .unwrap(); - } - - // wait for the message to be sent out - tokio::time::sleep(std::time::Duration::from_secs(1)).await; - - log::info!("fetching chats.."); - let chats = Chatlist::try_load(&ctx, 0, None, None).await.unwrap(); - - for i in 0..chats.len() { - let msg = Message::load_from_db(&ctx, chats.get_msg_id(i).unwrap().unwrap()) - .await - .unwrap(); - log::info!("[{}] msg: {:?}", i, msg); - } - - log::info!("stopping"); - ctx.stop_io().await; - log::info!("closing"); - drop(ctx); - events_spawn.await.unwrap(); -} From 17f2d3373161d2f61fd721c5ea983910974b67d0 Mon Sep 17 00:00:00 2001 From: Hocuri Date: Tue, 11 Jul 2023 19:15:23 +0200 Subject: [PATCH 006/102] test: Remove unnecessary inner_set_protection() call (#4539) 1:1 chats are automatically created as protected if the contact is verified, there is no need to explicitly do this. Plus, by removing this call, the test also tests that automatically creating 1:1 chats as protected works. --- src/tests/verified_chats.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/tests/verified_chats.rs b/src/tests/verified_chats.rs index 1967a320d..352b1d3ab 100644 --- a/src/tests/verified_chats.rs +++ b/src/tests/verified_chats.rs @@ -449,12 +449,7 @@ async fn test_break_protection_then_verify_again() -> Result<()> { mark_as_verified(&alice, &bob).await; mark_as_verified(&bob, &alice).await; - alice - .create_chat(&bob) - .await - .id - .inner_set_protection(&alice, ProtectionStatus::Protected) - .await?; + alice.create_chat(&bob).await; assert_verified(&alice, &bob, ProtectionStatus::Protected).await; tcm.section("Bob reinstalls DC"); From 1e28ea9bb0c9d05e5bc2398fafb59869251c6a19 Mon Sep 17 00:00:00 2001 From: Hocuri Date: Tue, 11 Jul 2023 19:39:59 +0200 Subject: [PATCH 007/102] fix: Don't create 1:1 chat as protected for contact who doesn't prefer to encrypt (#4538) --- src/chat.rs | 4 +++- src/tests/verified_chats.rs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/chat.rs b/src/chat.rs index cc34d79ab..3e8f1ad7c 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1999,7 +1999,9 @@ impl ChatIdBlocked { } let peerstate = Peerstate::from_addr(context, contact.get_addr()).await?; - let protected = peerstate.map_or(false, |p| p.is_using_verified_key()); + let protected = peerstate.map_or(false, |p| { + p.is_using_verified_key() && p.prefer_encrypt == EncryptPreference::Mutual + }); let smeared_time = create_smeared_timestamp(context); let chat_id = context diff --git a/src/tests/verified_chats.rs b/src/tests/verified_chats.rs index 352b1d3ab..e2c40e2a8 100644 --- a/src/tests/verified_chats.rs +++ b/src/tests/verified_chats.rs @@ -475,6 +475,43 @@ async fn test_break_protection_then_verify_again() -> Result<()> { Ok(()) } +/// Regression test: +/// - Verify a contact +/// - The contact stops using DC and sends a message from a classical MUA instead +/// - Delete the 1:1 chat +/// - Create a 1:1 chat +/// - Check that the created chat is not marked as protected +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_create_oneonone_chat_with_former_verified_contact() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + enable_verified_oneonone_chats(&[&alice]).await; + + mark_as_verified(&alice, &bob).await; + + receive_imf( + &alice, + b"Subject: Message from bob\r\n\ + From: \r\n\ + To: \r\n\ + Date: Mon, 12 Dec 2022 14:33:39 +0000\r\n\ + Message-ID: \r\n\ + \r\n\ + Heyho!\r\n", + false, + ) + .await + .unwrap() + .unwrap(); + + alice.create_chat(&bob).await; + + assert_verified(&alice, &bob, ProtectionStatus::Unprotected).await; + + Ok(()) +} + // ============== Helper Functions ============== async fn assert_verified(this: &TestContext, other: &TestContext, protected: ProtectionStatus) { From d762753103bae64241a7edffd8eee5cc389c9a4b Mon Sep 17 00:00:00 2001 From: Hocuri Date: Sun, 16 Jul 2023 12:04:43 +0200 Subject: [PATCH 008/102] fix: Allow to save a draft if the verification is broken (#4542) If the verification is broken, `can_send()` is false. But if the user was typing a message right when a verification-breaking message came in, the UI still needs to be able to save it as a draft. Steps to reproduce the bug: - Set a draft - Your chat partner breaks verification - Go back to the chats list - Go to the chat again - Accept the breakage - Expected: The draft is still there - Bug behavior: The draft is gone --- src/chat.rs | 8 -------- src/tests/verified_chats.rs | 25 ++++++++++++++++--------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/chat.rs b/src/chat.rs index 3e8f1ad7c..6e44cb8ff 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -761,14 +761,6 @@ impl ChatId { } } - let chat = Chat::load_from_db(context, self).await?; - if let Some(cant_send_reason) = chat.why_cant_send(context).await? { - bail!( - "Can't set a draft because chat is not writeable: {}", - cant_send_reason - ); - } - // set back draft information to allow identifying the draft later on - // no matter if message object is reused or reloaded from db msg.state = MessageState::OutDraft; diff --git a/src/tests/verified_chats.rs b/src/tests/verified_chats.rs index e2c40e2a8..5fb892c35 100644 --- a/src/tests/verified_chats.rs +++ b/src/tests/verified_chats.rs @@ -5,7 +5,7 @@ use crate::chat::{Chat, ProtectionStatus}; use crate::config::Config; use crate::contact::VerifiedStatus; use crate::contact::{Contact, Origin}; -use crate::message::Message; +use crate::message::{Message, Viewtype}; use crate::mimefactory::MimeFactory; use crate::mimeparser::SystemMessage; use crate::receive_imf::receive_imf; @@ -461,14 +461,21 @@ async fn test_break_protection_then_verify_again() -> Result<()> { tcm.send_recv(&bob_new, &alice, "I have a new device").await; assert_verified(&alice, &bob_new, ProtectionStatus::ProtectionBroken).await; - assert!( - !alice - .get_chat(&bob_new) - .await - .unwrap() - .can_send(&alice) - .await? - ); + + { + let alice_bob_chat = alice.get_chat(&bob_new).await.unwrap(); + assert!(!alice_bob_chat.can_send(&alice).await?); + + // Alice's UI should still be able to save a draft, which Alice started to type right when she got Bob's message: + let mut msg = Message::new(Viewtype::Text); + msg.set_text("Draftttt".to_string()); + alice_bob_chat.id.set_draft(&alice, Some(&mut msg)).await?; + assert_eq!( + alice_bob_chat.id.get_draft(&alice).await?.unwrap().text, + "Draftttt" + ); + } + tcm.execute_securejoin(&alice, &bob_new).await; assert_verified(&alice, &bob_new, ProtectionStatus::Protected).await; From 3de1dbc9e41b796ef0bd99ad715dc64ee3a4c703 Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 19 Jul 2023 13:26:47 +0000 Subject: [PATCH 009/102] chore(deps): update dependencies --- Cargo.lock | 287 +++++++++++++++++++++++++---------------------------- 1 file changed, 133 insertions(+), 154 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6030233cf..93b19ba6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,9 +89,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56fc6cf8dc8c4158eed8649f9b8b0ea1518eb62b544fe9490d66fa0b349eafe9" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" [[package]] name = "android-tzdata" @@ -131,9 +131,9 @@ checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" dependencies = [ "backtrace", ] @@ -169,7 +169,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.22", + "time 0.3.23", ] [[package]] @@ -197,9 +197,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", "event-listener", @@ -281,13 +281,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.70" +version = "0.1.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79fa67157abdfd688a259b6648808757db9347af834624f27ec646da976aee5d" +checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -312,9 +312,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" +checksum = "a6a1de45611fdb535bfde7b7de4fd54f4fd2b17b1737c0a59b69bf9b92074b8c" dependencies = [ "async-trait", "axum-core", @@ -448,9 +448,9 @@ checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" [[package]] name = "blake3" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729b71f35bd3fa1a4c86b85d32c8b9069ea7fe14f7a53cfabb65f62d4265b888" +checksum = "199c42ab6972d92c9f8995f086273d25c42fc0f7b2a1fcefba465c1352d25ba5" dependencies = [ "arrayref", "arrayvec", @@ -520,9 +520,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5" +checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" dependencies = [ "memchr", "serde", @@ -584,18 +584,18 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.4" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" dependencies = [ "serde", ] @@ -713,18 +713,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.10" +version = "4.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a" +checksum = "74bb1b4028935821b2d6b439bba2e970bdcf740832732437ead910c632e30d7d" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.3.10" +version = "4.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d" +checksum = "5ae467cbb0111869b765e13882a1dbbd6cb52f58203d8b80c44f667d4dd19843" dependencies = [ "anstyle", "clap_lex", @@ -770,9 +770,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6340df57935414636969091153f35f68d9f00bbc8fb4a9c6054706c213e6c6bc" +checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747" [[package]] name = "const_format" @@ -796,9 +796,9 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "convert_case" @@ -830,9 +830,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -977,16 +977,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "ctor" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" -dependencies = [ - "quote", - "syn 1.0.109", -] - [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -1025,7 +1015,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -1258,7 +1248,7 @@ name = "deltachat_derive" version = "2.0.0" dependencies = [ "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -1458,7 +1448,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -1486,9 +1476,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" +checksum = "304e6508efa593091e97a9abbc10f90aa7ca635b6d2784feff3c89d41dd12272" [[package]] name = "ecdsa" @@ -1617,7 +1607,7 @@ dependencies = [ "pem-rfc7468 0.7.0", "pkcs8 0.10.2", "rand_core 0.6.4", - "sec1 0.7.2", + "sec1 0.7.3", "subtle", "zeroize", ] @@ -1758,7 +1748,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -1776,9 +1766,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" @@ -1876,7 +1866,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ "cfg-if", - "rustix 0.38.2", + "rustix 0.38.4", "windows-sys 0.48.0", ] @@ -2055,7 +2045,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -2567,12 +2557,12 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.2", + "rustix 0.38.4", "windows-sys 0.48.0", ] @@ -2587,9 +2577,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jpeg-decoder" @@ -3005,7 +2995,7 @@ checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -3119,7 +3109,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -3167,15 +3157,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - [[package]] name = "overload" version = "0.1.1" @@ -3259,9 +3240,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pem" @@ -3364,7 +3345,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -3477,15 +3458,15 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.3.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794" +checksum = "edc55135a600d700580e406b4de0d59cb9ad25e344a3a091a97ded2622ec4ec6" [[package]] name = "postcard" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa512cd0d087cc9f99ad30a1bf64795b67871edbead083ffc3a4dfafa59aa00" +checksum = "c9ee729232311d3cd113749948b689627618133b1c5012b77342c1950b25eaeb" dependencies = [ "cobs", "const_format", @@ -3512,13 +3493,11 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "pretty_assertions" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ - "ctor", "diff", - "output_vt100", "yansi", ] @@ -3567,9 +3546,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -3680,9 +3659,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.29" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" dependencies = [ "proc-macro2", ] @@ -3817,7 +3796,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring", - "time 0.3.22", + "time 0.3.23", "yasna", ] @@ -3858,7 +3837,7 @@ checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.2", + "regex-syntax 0.7.4", ] [[package]] @@ -3878,9 +3857,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "reqwest" @@ -4068,9 +4047,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.22" +version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8818fa822adcc98b18fedbb3632a6a33213c070556b5aa7c4c8cc21cff565c4c" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ "bitflags 1.3.2", "errno", @@ -4082,9 +4061,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.2" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aabcb0461ebd01d6b79945797c27f8529082226cb630a9865a71870ff63532a4" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" dependencies = [ "bitflags 2.3.3", "errno", @@ -4127,9 +4106,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "rustyline" @@ -4156,9 +4135,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "safemem" @@ -4220,9 +4199,9 @@ dependencies = [ [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" @@ -4250,9 +4229,9 @@ dependencies = [ [[package]] name = "sec1" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct 0.2.0", "der 0.7.7", @@ -4293,18 +4272,18 @@ checksum = "4c309e515543e67811222dbc9e3dd7e1056279b782e1dacffe4242b718734fb6" [[package]] name = "semver" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.166" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01b7404f9d441d3ad40e6a636a7782c377d2abdbe4fa2440e2edcc2f4f10db8" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] @@ -4320,22 +4299,22 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.10" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c5113243e4a3a1c96587342d067f3e6b0f50790b6cf40d2868eb647a3eef0e" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.166" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd83d6dde2b6b2d466e14d9d1acce8816dedee94f735eac6395808b3483c6d6" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -4351,9 +4330,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.100" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" +checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" dependencies = [ "itoa", "ryu", @@ -4362,9 +4341,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b1b6471d7496b051e03f1958802a73f88b947866f5146f329e47e36554f4e55" +checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" dependencies = [ "itoa", "serde", @@ -4502,9 +4481,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "smawk" @@ -4648,7 +4627,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -4670,9 +4649,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.23" +version = "2.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" +checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" dependencies = [ "proc-macro2", "quote", @@ -4734,9 +4713,9 @@ dependencies = [ [[package]] name = "tagger" -version = "4.3.4" +version = "4.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aaa6f5d645d1dae4cd0286e9f8bf15b75a31656348e5e106eb1a940abd34b63" +checksum = "094c9f64d6de9a8506b1e49b63a29333b37ed9e821ee04be694d431b3264c3c5" [[package]] name = "tempfile" @@ -4748,7 +4727,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.22", + "rustix 0.37.23", "windows-sys 0.48.0", ] @@ -4788,22 +4767,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.41" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c16a64ba9387ef3fdae4f9c1a7f07a0997fce91985c0336f1ddc1822b3b37802" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.41" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d14928354b01c4d6a4f0e549069adef399a284e7995c7ccca94e8a07a5346c59" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -4829,9 +4808,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" dependencies = [ "itoa", "serde", @@ -4847,9 +4826,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" dependencies = [ "time-core", ] @@ -4917,7 +4896,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -4973,9 +4952,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" +checksum = "ec509ac96e9a0c43427c74f003127d953a265737636129424288d27cb5c4b12c" dependencies = [ "futures-util", "log", @@ -4999,9 +4978,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" dependencies = [ "serde", "serde_spanned", @@ -5020,9 +4999,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.11" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ "indexmap 2.0.0", "serde", @@ -5080,7 +5059,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] [[package]] @@ -5185,13 +5164,13 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "tungstenite" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" +checksum = "15fba1a6d6bb030745759a9a2a588bfe8490fc8b4751a277db3a0be1c9ebbf67" dependencies = [ - "base64 0.13.1", "byteorder", "bytes", + "data-encoding", "http", "httparse", "log", @@ -5219,9 +5198,9 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "typescript-type-def" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e6b74ffbd5684d318252bb7182051df8c4ecc098b542f63fddf792e7f42aa02" +checksum = "3c4be05eb0171e18da471e545cfff85d80b8118e5aa2d50c2d152265d7435997" dependencies = [ "serde_json", "typescript-type-def-derive", @@ -5229,9 +5208,9 @@ dependencies = [ [[package]] name = "typescript-type-def-derive" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b10a4f5dd87c279f90beef31edb7055bfd1ceb66e73148de107a5c9005e9f864" +checksum = "71aeb2295da6c2bfe665493332b4e4281d113fab3a0786e9651dcc85708095a4" dependencies = [ "darling 0.13.4", "ident_case", @@ -5255,9 +5234,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-linebreak" @@ -5327,9 +5306,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" dependencies = [ "getrandom 0.2.10", "serde", @@ -5417,7 +5396,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", "wasm-bindgen-shared", ] @@ -5451,7 +5430,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5721,9 +5700,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.7" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" dependencies = [ "memchr", ] @@ -5773,7 +5752,7 @@ dependencies = [ "oid-registry", "rusticata-macros", "thiserror", - "time 0.3.22", + "time 0.3.23", ] [[package]] @@ -5797,7 +5776,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ - "time 0.3.22", + "time 0.3.23", ] [[package]] @@ -5853,5 +5832,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.26", ] From a1663a98e08a40ddb651462477db9ebc5dd7c0c7 Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 19 Jul 2023 13:40:41 +0000 Subject: [PATCH 010/102] build: use Rust 1.71.0 and increase MSRV to 1.66.0 Rust 1.66 is required by constant_time_eq 0.3.0. --- .github/workflows/ci.yml | 12 ++++++------ Cargo.toml | 2 +- scripts/zig-musl-check.sh | 2 +- scripts/zig-rpc-server.sh | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cd2d085b7..31d681269 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: name: Lint Rust runs-on: ubuntu-latest env: - RUSTUP_TOOLCHAIN: 1.70.0 + RUSTUP_TOOLCHAIN: 1.71.0 steps: - uses: actions/checkout@v3 - name: Install rustfmt and clippy @@ -80,19 +80,19 @@ jobs: matrix: include: - os: ubuntu-latest - rust: 1.68.2 + rust: 1.71.0 - os: windows-latest - rust: 1.68.2 + rust: 1.71.0 - os: macos-latest - rust: 1.68.2 + rust: 1.71.0 - # Minimum Supported Rust Version = 1.65.0 + # Minimum Supported Rust Version = 1.66.0 # # Minimum Supported Python Version = 3.7 # This is the minimum version for which manylinux Python wheels are # built. - os: ubuntu-latest - rust: 1.65.0 + rust: 1.66.0 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 diff --git a/Cargo.toml b/Cargo.toml index 012ad268f..57efe378f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "deltachat" version = "1.118.0" edition = "2021" license = "MPL-2.0" -rust-version = "1.65" +rust-version = "1.66" [profile.dev] debug = 0 diff --git a/scripts/zig-musl-check.sh b/scripts/zig-musl-check.sh index 1e4afd6db..19d30d2cf 100755 --- a/scripts/zig-musl-check.sh +++ b/scripts/zig-musl-check.sh @@ -9,7 +9,7 @@ set -e unset RUSTFLAGS # Pin Rust version to avoid uncontrolled changes in the compiler and linker flags. -export RUSTUP_TOOLCHAIN=1.70.0 +export RUSTUP_TOOLCHAIN=1.71.0 ZIG_VERSION=0.11.0-dev.2213+515e1c93e diff --git a/scripts/zig-rpc-server.sh b/scripts/zig-rpc-server.sh index ee96905bb..29e16121c 100755 --- a/scripts/zig-rpc-server.sh +++ b/scripts/zig-rpc-server.sh @@ -8,7 +8,7 @@ set -e unset RUSTFLAGS # Pin Rust version to avoid uncontrolled changes in the compiler and linker flags. -export RUSTUP_TOOLCHAIN=1.70.0 +export RUSTUP_TOOLCHAIN=1.71.0 ZIG_VERSION=0.11.0-dev.2213+515e1c93e From 659cffe0cc8a27da160e8e4c0ae45808e7294ed1 Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 19 Jul 2023 13:43:20 +0000 Subject: [PATCH 011/102] ci: remove comment about python from rust tests --- .github/workflows/ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 31d681269..2a61e289b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,10 +87,6 @@ jobs: rust: 1.71.0 # Minimum Supported Rust Version = 1.66.0 - # - # Minimum Supported Python Version = 3.7 - # This is the minimum version for which manylinux Python wheels are - # built. - os: ubuntu-latest rust: 1.66.0 runs-on: ${{ matrix.os }} From 7062bb0502ba863b73944d9cbccc59f6e4b652ea Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 18 Jul 2023 13:55:18 +0200 Subject: [PATCH 012/102] clarify transitive behaviour of dc_contact_is_verfified() --- deltachat-ffi/deltachat.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index fdc72f20f..b55b9df30 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -5017,7 +5017,12 @@ int dc_contact_is_verified (dc_contact_t* contact); /** * Return the address that verified a contact * - * The UI may use this in addition to a checkmark showing the verification status + * The UI may use this in addition to a checkmark showing the verification status. + * In case of verification chains, + * the last contact in the chain is shown. + * This is because of privacy reasons, but also as it would not help the user + * to see a unknown name here - where one can mostly always ask the shown name + * as it is directly known. * * @memberof dc_contact_t * @param contact The contact object. From 567329462335efde94c091db733136c8c2280ccb Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Jul 2023 18:43:52 +0200 Subject: [PATCH 013/102] api(jsonrpc): add resend_messages --- deltachat-jsonrpc/src/api/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/deltachat-jsonrpc/src/api/mod.rs b/deltachat-jsonrpc/src/api/mod.rs index 617f1d6c4..7c5c8e311 100644 --- a/deltachat-jsonrpc/src/api/mod.rs +++ b/deltachat-jsonrpc/src/api/mod.rs @@ -1709,6 +1709,24 @@ impl CommandApi { forward_msgs(&ctx, &message_ids, ChatId::new(chat_id)).await } + /// Resend messages and make information available for newly added chat members. + /// Resending sends out the original message, however, recipients and webxdc-status may differ. + /// Clients that already have the original message can still ignore the resent message as + /// they have tracked the state by dedicated updates. + /// + /// Some messages cannot be resent, eg. info-messages, drafts, already pending messages or messages that are not sent by SELF. + /// + /// message_ids all message IDs that should be resend. All messages must belong to the same chat. + async fn resend_messages( + &self, + account_id: u32, + message_ids: Vec, + ) -> Result<()> { + let ctx = self.get_context(account_id).await?; + let message_ids: Vec = message_ids.into_iter().map(MsgId::new).collect(); + chat::resend_msgs(&ctx, &message_ids).await + } + async fn send_sticker( &self, account_id: u32, From b8fcb660ad2c8c256c6eecb83e2325c076ace9bf Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Jul 2023 18:53:47 +0200 Subject: [PATCH 014/102] cargo fmt --- deltachat-jsonrpc/src/api/mod.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/deltachat-jsonrpc/src/api/mod.rs b/deltachat-jsonrpc/src/api/mod.rs index 7c5c8e311..d9b6db8aa 100644 --- a/deltachat-jsonrpc/src/api/mod.rs +++ b/deltachat-jsonrpc/src/api/mod.rs @@ -1717,11 +1717,7 @@ impl CommandApi { /// Some messages cannot be resent, eg. info-messages, drafts, already pending messages or messages that are not sent by SELF. /// /// message_ids all message IDs that should be resend. All messages must belong to the same chat. - async fn resend_messages( - &self, - account_id: u32, - message_ids: Vec, - ) -> Result<()> { + async fn resend_messages(&self, account_id: u32, message_ids: Vec) -> Result<()> { let ctx = self.get_context(account_id).await?; let message_ids: Vec = message_ids.into_iter().map(MsgId::new).collect(); chat::resend_msgs(&ctx, &message_ids).await From 3a63628f1fcd5f6f58656490006706aa45e04add Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Jul 2023 18:50:05 +0200 Subject: [PATCH 015/102] update node constants looks like this was fogotten when changing the chat protection stock strings --- node/constants.js | 8 ++------ node/lib/constants.ts | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/node/constants.js b/node/constants.js index d55d92782..ad464c81a 100644 --- a/node/constants.js +++ b/node/constants.js @@ -158,6 +158,8 @@ module.exports = { DC_STR_BROADCAST_LIST: 115, DC_STR_CANNOT_LOGIN: 60, DC_STR_CANTDECRYPT_MSG_BODY: 29, + DC_STR_CHAT_PROTECTION_DISABLED: 171, + DC_STR_CHAT_PROTECTION_ENABLED: 170, DC_STR_CONFIGURATION_FAILED: 84, DC_STR_CONNECTED: 107, DC_STR_CONNTECTING: 108, @@ -243,12 +245,6 @@ module.exports = { DC_STR_OUTGOING_MESSAGES: 104, DC_STR_PARTIAL_DOWNLOAD_MSG_BODY: 99, DC_STR_PART_OF_TOTAL_USED: 116, - DC_STR_PROTECTION_DISABLED: 89, - DC_STR_PROTECTION_DISABLED_BY_OTHER: 161, - DC_STR_PROTECTION_DISABLED_BY_YOU: 160, - DC_STR_PROTECTION_ENABLED: 88, - DC_STR_PROTECTION_ENABLED_BY_OTHER: 159, - DC_STR_PROTECTION_ENABLED_BY_YOU: 158, DC_STR_QUOTA_EXCEEDING_MSG_BODY: 98, DC_STR_READRCPT: 31, DC_STR_READRCPT_MAILBODY: 32, diff --git a/node/lib/constants.ts b/node/lib/constants.ts index cacbd570d..76b7707f7 100644 --- a/node/lib/constants.ts +++ b/node/lib/constants.ts @@ -158,6 +158,8 @@ export enum C { DC_STR_BROADCAST_LIST = 115, DC_STR_CANNOT_LOGIN = 60, DC_STR_CANTDECRYPT_MSG_BODY = 29, + DC_STR_CHAT_PROTECTION_DISABLED = 171, + DC_STR_CHAT_PROTECTION_ENABLED = 170, DC_STR_CONFIGURATION_FAILED = 84, DC_STR_CONNECTED = 107, DC_STR_CONNTECTING = 108, @@ -243,12 +245,6 @@ export enum C { DC_STR_OUTGOING_MESSAGES = 104, DC_STR_PARTIAL_DOWNLOAD_MSG_BODY = 99, DC_STR_PART_OF_TOTAL_USED = 116, - DC_STR_PROTECTION_DISABLED = 89, - DC_STR_PROTECTION_DISABLED_BY_OTHER = 161, - DC_STR_PROTECTION_DISABLED_BY_YOU = 160, - DC_STR_PROTECTION_ENABLED = 88, - DC_STR_PROTECTION_ENABLED_BY_OTHER = 159, - DC_STR_PROTECTION_ENABLED_BY_YOU = 158, DC_STR_QUOTA_EXCEEDING_MSG_BODY = 98, DC_STR_READRCPT = 31, DC_STR_READRCPT_MAILBODY = 32, From 682e241edbf4281279bd4dc8dff1a4cf2c036242 Mon Sep 17 00:00:00 2001 From: Hocuri Date: Mon, 24 Jul 2023 12:16:32 +0200 Subject: [PATCH 016/102] fix: Fix info-message orderings of verified 1:1 chats (#4545) Correctly handle messages with old timestamps for verified chats: * They must not be sorted over a protection-changed info message * If they change the protection, then they must not be sorted over existing other messages, because then the protection-changed info message would also be above these existing messages. This PR fixes this: 1. Even seen messages can't be sorted into already-noticed messages anymore. **This also changes DC's behavior in the absence of verified 1:1 chats**. Before this PR, messages that are marked as seen when they are downloaded will always be sorted by their timestamp, even if it's very old. 2. protection-changed info messages are always sorted to the bottom. **Edit:** 3. There is an exception to rule 1: Outgoing messages are still allowed to be sorted purely by their timestamp, and don't influence old messages. This is to the problem described at [*]. Together, these rules also make sure that the protection-changed info message is always right above the message causing the change. [*] If we receive messages from two different folders, e.g. `Sent` and `Inbox`, then this will lead to wrong message ordering in many cases. I need to think about this more, or maybe someone else has an idea. One new idea that came to my mind is: * Always sort noticed messages under the newest info message (this PR sorts them under the newest noticed message, master sorts them purely by their sent timestamp) * Always sort unnoticed messages under the newest noticed message (that's the same behavior as in this PR and on master) * Always sort protection-changed info messages to the bottom (as in this PR) However, after a talk with @link2xt we instead decided to add rule 3. (see above) because it seemed a little bit easier. --- src/receive_imf.rs | 49 +++++--- src/tests/verified_chats.rs | 167 ++++++++++++++++++++++++++++ test-data/golden/test_old_message_1 | 6 + test-data/golden/test_old_message_2 | 7 ++ test-data/golden/test_old_message_3 | 7 ++ 5 files changed, 222 insertions(+), 14 deletions(-) create mode 100644 test-data/golden/test_old_message_1 create mode 100644 test-data/golden/test_old_message_2 create mode 100644 test-data/golden/test_old_message_3 diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 010ba31df..4222e69ab 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -754,8 +754,12 @@ async fn add_parts( new_protection = ProtectionStatus::ProtectionBroken; } + // The message itself will be sorted under the device message since the device + // message is `MessageState::InNoticed`, which means that all following + // messages are sorted under it. let sort_timestamp = - calc_sort_timestamp(context, sent_timestamp, chat_id, true).await?; + calc_sort_timestamp(context, sent_timestamp, chat_id, true, incoming) + .await?; chat_id .set_protection(context, new_protection, sort_timestamp, Some(from_id)) .await?; @@ -948,7 +952,8 @@ async fn add_parts( }; let in_fresh = state == MessageState::InFresh; - let sort_timestamp = calc_sort_timestamp(context, sent_timestamp, chat_id, in_fresh).await?; + let sort_timestamp = + calc_sort_timestamp(context, sent_timestamp, chat_id, false, incoming).await?; // Apply ephemeral timer changes to the chat. // @@ -1376,25 +1381,41 @@ async fn calc_sort_timestamp( context: &Context, message_timestamp: i64, chat_id: ChatId, - is_fresh_msg: bool, + always_sort_to_bottom: bool, + incoming: bool, ) -> Result { let mut sort_timestamp = message_timestamp; - // get newest non fresh message for this chat - // update sort_timestamp if less than that - if is_fresh_msg { - let last_msg_time: Option = context + let last_msg_time: Option = if always_sort_to_bottom { + // get newest message for this chat + context .sql .query_get_value( - "SELECT MAX(timestamp) FROM msgs WHERE chat_id=? AND state>?", - (chat_id, MessageState::InFresh), + "SELECT MAX(timestamp) FROM msgs WHERE chat_id=?", + (chat_id,), ) - .await?; + .await? + } else if incoming { + // get newest incoming non fresh message for this chat. - if let Some(last_msg_time) = last_msg_time { - if last_msg_time > sort_timestamp { - sort_timestamp = last_msg_time; - } + // If a user hasn't been online for some time, the Inbox is + // fetched first and then the Sentbox. In order for Inbox + // and Sent messages to be allowed to mingle, + // outgoing messages are purely sorted by their sent timestamp. + context + .sql + .query_get_value( + "SELECT MAX(timestamp) FROM msgs WHERE chat_id=? AND state>? AND from_id!=?", + (chat_id, MessageState::InFresh, ContactId::SELF), + ) + .await? + } else { + None + }; + + if let Some(last_msg_time) = last_msg_time { + if last_msg_time > sort_timestamp { + sort_timestamp = last_msg_time; } } diff --git a/src/tests/verified_chats.rs b/src/tests/verified_chats.rs index 5fb892c35..e8a8f3e7f 100644 --- a/src/tests/verified_chats.rs +++ b/src/tests/verified_chats.rs @@ -313,6 +313,173 @@ async fn test_verified_oneonone_chat_enable_disable() -> Result<()> { Ok(()) } +/// Messages with old timestamps are difficult for verified chats: +/// - They must not be sorted over a protection-changed info message. +/// That's what `test_old_message_2` tests +/// - If they change the protection, then they must not be sorted over existing other messages, +/// because then the protection-changed info message would also be above these existing messages. +/// That's what `test_old_message_3` tests. +/// +/// `test_old_message_1` tests the case where both the old and the new message +/// change verification +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_old_message_1() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + enable_verified_oneonone_chats(&[&alice, &bob]).await; + + mark_as_verified(&alice, &bob).await; + + let chat = alice.create_chat(&bob).await; // This creates a protection-changed info message + assert!(chat.is_protected()); + + // This creates protection-changed info message #2; + // even though the date is old, info message and email must be sorted below the original info message. + receive_imf( + &alice, + b"From: Bob \n\ + To: alice@example.org\n\ + Message-ID: <1234-2-3@example.org>\n\ + Date: Sat, 07 Dec 2019 19:00:27 +0000\n\ + \n\ + Message from Thunderbird\n", + true, + ) + .await?; + + alice.golden_test_chat(chat.id, "test_old_message_1").await; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_old_message_2() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + enable_verified_oneonone_chats(&[&alice, &bob]).await; + + mark_as_verified(&alice, &bob).await; + + // This creates protection-changed info message #1: + let chat = alice.create_chat(&bob).await; + assert!(chat.is_protected()); + let protection_msg = alice.get_last_msg().await; + assert_eq!( + protection_msg.param.get_cmd(), + SystemMessage::ChatProtectionEnabled + ); + + // This creates protection-changed info message #2. + let first_email = receive_imf( + &alice, + b"From: Bob \n\ + To: alice@example.org\n\ + Message-ID: <1234-2-3@example.org>\n\ + Date: Sun, 08 Dec 2019 19:00:27 +0000\n\ + \n\ + Somewhat old message\n", + false, + ) + .await? + .unwrap(); + + // Both messages will get the same timestamp as the protection-changed + // message, so this one will be sorted under the previous one + // even though it has an older timestamp. + let second_email = receive_imf( + &alice, + b"From: Bob \n\ + To: alice@example.org\n\ + Message-ID: <2319-2-3@example.org>\n\ + Date: Sat, 07 Dec 2019 19:00:27 +0000\n\ + \n\ + Even older message, that must NOT be shown before the info message\n", + true, + ) + .await? + .unwrap(); + + assert_eq!(first_email.sort_timestamp, second_email.sort_timestamp); + assert_eq!(first_email.sort_timestamp, protection_msg.timestamp_sort); + + alice.golden_test_chat(chat.id, "test_old_message_2").await; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_old_message_3() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + enable_verified_oneonone_chats(&[&alice, &bob]).await; + + mark_as_verified(&alice, &bob).await; + mark_as_verified(&bob, &alice).await; + + tcm.send_recv_accept(&bob, &alice, "Heyho from my verified device!") + .await; + + // This unverified message must not be sorted over the message sent in the previous line: + receive_imf( + &alice, + b"From: Bob \n\ + To: alice@example.org\n\ + Message-ID: <1234-2-3@example.org>\n\ + Date: Sat, 07 Dec 2019 19:00:27 +0000\n\ + \n\ + Old, unverified message\n", + true, + ) + .await?; + + alice + .golden_test_chat(alice.get_chat(&bob).await.unwrap().id, "test_old_message_3") + .await; + + Ok(()) +} + +/// Alice is offline for some time. +/// When she comes online, first her inbox is synced and then her sentbox. +/// This test tests that the messages are still in the right order. +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_old_message_4() -> Result<()> { + let alice = TestContext::new_alice().await; + let msg_incoming = receive_imf( + &alice, + b"From: Bob \n\ + To: alice@example.org\n\ + Message-ID: <1234-2-3@example.org>\n\ + Date: Sun, 08 Dec 2019 19:00:27 +0000\n\ + \n\ + Thanks, Alice!\n", + true, + ) + .await? + .unwrap(); + + let msg_sent = receive_imf( + &alice, + b"From: alice@example.org\n\ + To: Bob \n\ + Message-ID: <1234-2-4@example.org>\n\ + Date: Sat, 07 Dec 2019 19:00:27 +0000\n\ + \n\ + Happy birthday, Bob!\n", + true, + ) + .await? + .unwrap(); + + // The "Happy birthday" message should be shown first, and then the "Thanks" message + assert!(msg_sent.sort_timestamp < msg_incoming.sort_timestamp); + + Ok(()) +} + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mdn_doesnt_disable_verification() -> Result<()> { let mut tcm = TestContextManager::new(); diff --git a/test-data/golden/test_old_message_1 b/test-data/golden/test_old_message_1 new file mode 100644 index 000000000..61e54d298 --- /dev/null +++ b/test-data/golden/test_old_message_1 @@ -0,0 +1,6 @@ +Single#Chat#10: Bob [bob@example.net] +-------------------------------------------------------------------------------- +Msg#10: info (Contact#Contact#Info): Messages are guaranteed to be end-to-end encrypted from now on. [NOTICED][INFO 🛡️] +Msg#11: info (Contact#Contact#Info): Bob sent a message from another device. [NOTICED][INFO 🛡️❌] +Msg#12: (Contact#Contact#10): Message from Thunderbird [SEEN] +-------------------------------------------------------------------------------- diff --git a/test-data/golden/test_old_message_2 b/test-data/golden/test_old_message_2 new file mode 100644 index 000000000..d7e7712ab --- /dev/null +++ b/test-data/golden/test_old_message_2 @@ -0,0 +1,7 @@ +Single#Chat#10: Bob [bob@example.net] +-------------------------------------------------------------------------------- +Msg#10: info (Contact#Contact#Info): Messages are guaranteed to be end-to-end encrypted from now on. [NOTICED][INFO 🛡️] +Msg#11: info (Contact#Contact#Info): Bob sent a message from another device. [NOTICED][INFO 🛡️❌] +Msg#12: (Contact#Contact#10): Somewhat old message [FRESH] +Msg#13: (Contact#Contact#10): Even older message, that must NOT be shown before the info message [SEEN] +-------------------------------------------------------------------------------- diff --git a/test-data/golden/test_old_message_3 b/test-data/golden/test_old_message_3 new file mode 100644 index 000000000..30d5ed041 --- /dev/null +++ b/test-data/golden/test_old_message_3 @@ -0,0 +1,7 @@ +Single#Chat#10: Bob [bob@example.net] +-------------------------------------------------------------------------------- +Msg#10: info (Contact#Contact#Info): Messages are guaranteed to be end-to-end encrypted from now on. [NOTICED][INFO 🛡️] +Msg#11🔒: (Contact#Contact#10): Heyho from my verified device! [FRESH] +Msg#12: info (Contact#Contact#Info): Bob sent a message from another device. [NOTICED][INFO 🛡️❌] +Msg#13: (Contact#Contact#10): Old, unverified message [SEEN] +-------------------------------------------------------------------------------- From b96028cd87f02a83f8f0a5282da4b4bb88cdc05c Mon Sep 17 00:00:00 2001 From: Hocuri Date: Mon, 24 Jul 2023 12:19:13 +0200 Subject: [PATCH 017/102] api!(Rust): Remove unused function is_verified_ex() (#4551) No one used it anymore, and all occurences I could find (on GitHub)[https://github.com/search?q=%22is_verified_ex%22&type=code&p=1] are either forks of deltachat-core-rust or of deltachat-core (which is the old C core). --- src/contact.rs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/contact.rs b/src/contact.rs index a5a400214..9492ffd09 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -1213,28 +1213,13 @@ impl Contact { /// The UI may draw a checkbox or something like that beside verified contacts. /// pub async fn is_verified(&self, context: &Context) -> Result { - self.is_verified_ex(context, None).await - } - - /// Same as `Contact::is_verified` but allows speeding up things - /// by adding the peerstate belonging to the contact. - /// If you do not have the peerstate available, it is loaded automatically. - pub async fn is_verified_ex( - &self, - context: &Context, - peerstate: Option<&Peerstate>, - ) -> Result { // We're always sort of secured-verified as we could verify the key on this device any time with the key // on this device if self.id == ContactId::SELF { return Ok(VerifiedStatus::BidirectVerified); } - if let Some(peerstate) = peerstate { - if peerstate.verified_key.is_some() { - return Ok(VerifiedStatus::BidirectVerified); - } - } else if let Some(peerstate) = Peerstate::from_addr(context, &self.addr).await? { + if let Some(peerstate) = Peerstate::from_addr(context, &self.addr).await? { if peerstate.verified_key.is_some() { return Ok(VerifiedStatus::BidirectVerified); } From 8fb8a877befcdd43a9790ee0040eb38f007b9b1b Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 24 Jul 2023 14:06:09 +0000 Subject: [PATCH 018/102] chore(deps): update dependencies --- Cargo.lock | 148 ++++++++++++++++++++++------------------------------- deny.toml | 5 +- 2 files changed, 63 insertions(+), 90 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 93b19ba6d..d547ea4a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -281,13 +281,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.71" +version = "0.1.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" +checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -713,18 +713,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.16" +version = "4.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74bb1b4028935821b2d6b439bba2e970bdcf740832732437ead910c632e30d7d" +checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.3.16" +version = "4.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ae467cbb0111869b765e13882a1dbbd6cb52f58203d8b80c44f667d4dd19843" +checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" dependencies = [ "anstyle", "clap_lex", @@ -1015,7 +1015,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -1248,7 +1248,7 @@ name = "deltachat_derive" version = "2.0.0" dependencies = [ "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -1448,7 +1448,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -1494,9 +1494,9 @@ dependencies = [ [[package]] name = "ecdsa" -version = "0.16.7" +version = "0.16.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" dependencies = [ "der 0.7.7", "digest 0.10.7", @@ -1568,9 +1568,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "elliptic-curve" @@ -1748,7 +1748,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -1859,6 +1859,12 @@ dependencies = [ "instant", ] +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + [[package]] name = "fd-lock" version = "3.0.13" @@ -1866,7 +1872,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ "cfg-if", - "rustix 0.38.4", + "rustix", "windows-sys 0.48.0", ] @@ -2028,7 +2034,7 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" dependencies = [ - "fastrand", + "fastrand 1.9.0", "futures-core", "futures-io", "memchr", @@ -2045,7 +2051,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -2482,17 +2488,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "ipconfig" version = "0.3.2" @@ -2562,7 +2557,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.4", + "rustix", "windows-sys 0.48.0", ] @@ -2677,12 +2672,6 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - [[package]] name = "linux-raw-sys" version = "0.4.3" @@ -2995,7 +2984,7 @@ checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -3032,9 +3021,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", "libm", @@ -3109,7 +3098,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -3180,7 +3169,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ - "ecdsa 0.16.7", + "ecdsa 0.16.8", "elliptic-curve 0.13.5", "primeorder", "sha2 0.10.7", @@ -3203,7 +3192,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" dependencies = [ - "ecdsa 0.16.7", + "ecdsa 0.16.8", "elliptic-curve 0.13.5", "primeorder", "sha2 0.10.7", @@ -3345,7 +3334,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -3659,9 +3648,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.31" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -4045,20 +4034,6 @@ dependencies = [ "nom", ] -[[package]] -name = "rustix" -version = "0.37.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - [[package]] name = "rustix" version = "0.38.4" @@ -4068,7 +4043,7 @@ dependencies = [ "bitflags 2.3.3", "errno", "libc", - "linux-raw-sys 0.4.3", + "linux-raw-sys", "windows-sys 0.48.0", ] @@ -4243,9 +4218,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -4256,9 +4231,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", @@ -4281,9 +4256,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.171" +version = "1.0.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" +checksum = "5d25439cd7397d044e2748a6fe2432b5e85db703d6d097bd014b3c0ad1ebff0b" dependencies = [ "serde_derive", ] @@ -4308,13 +4283,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.171" +version = "1.0.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" +checksum = "b23f7ade6f110613c0d63858ddb8b94c1041f550eab58a16b371bdf2c9c80ab4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -4627,7 +4602,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -4649,9 +4624,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.26" +version = "2.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" +checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" dependencies = [ "proc-macro2", "quote", @@ -4719,15 +4694,14 @@ checksum = "094c9f64d6de9a8506b1e49b63a29333b37ed9e821ee04be694d431b3264c3c5" [[package]] name = "tempfile" -version = "3.6.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" dependencies = [ - "autocfg", "cfg-if", - "fastrand", + "fastrand 2.0.0", "redox_syscall 0.3.5", - "rustix 0.37.23", + "rustix", "windows-sys 0.48.0", ] @@ -4767,22 +4741,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -4896,7 +4870,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -5059,7 +5033,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -5396,7 +5370,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", "wasm-bindgen-shared", ] @@ -5430,7 +5404,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5832,5 +5806,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] diff --git a/deny.toml b/deny.toml index b86f87556..b9c4b7432 100644 --- a/deny.toml +++ b/deny.toml @@ -24,11 +24,11 @@ skip = [ { name = "digest", version = "<0.10" }, { name = "ed25519-dalek", version = "1.0.1" }, { name = "ed25519", version = "1.5.3" }, + { name = "fastrand", version = "1.9.0" }, { name = "getrandom", version = "<0.2" }, { name = "hashbrown", version = "<0.14.0" }, { name = "idna", version = "<0.3" }, { name = "indexmap", version = "<2.0.0" }, - { name = "linux-raw-sys", version = "0.3.8" }, { name = "num-derive", version = "0.3.3" }, { name = "pem-rfc7468", version = "0.6.0" }, { name = "pkcs8", version = "0.9.0" }, @@ -38,7 +38,6 @@ skip = [ { name = "rand", version = "<0.8" }, { name = "redox_syscall", version = "0.2.16" }, { name = "regex-syntax", version = "0.6.29" }, - { name = "rustix", version = "0.37.21" }, { name = "sec1", version = "0.3.0" }, { name = "sha2", version = "<0.10" }, { name = "signature", version = "1.6.4" }, @@ -54,8 +53,8 @@ skip = [ { name = "windows_i686_msvc", version = "<0.48" }, { name = "windows-sys", version = "<0.48" }, { name = "windows-targets", version = "<0.48" }, - { name = "windows_x86_64_gnullvm", version = "<0.48" }, { name = "windows", version = "0.32.0" }, + { name = "windows_x86_64_gnullvm", version = "<0.48" }, { name = "windows_x86_64_gnu", version = "<0.48" }, { name = "windows_x86_64_msvc", version = "<0.48" }, { name = "winreg", version = "0.10.1" }, From acc7bb00c584671b46a12eb32cc14cc9bae8b5c3 Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 24 Jul 2023 16:14:16 +0000 Subject: [PATCH 019/102] chore(deps): update rPGP --- Cargo.lock | 34 +++++++++++++--------------------- deny.toml | 1 - 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d547ea4a3..27ea5bd48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1145,7 +1145,7 @@ dependencies = [ "log", "mailparse", "mime", - "num-derive 0.4.0", + "num-derive", "num-traits", "num_cpus", "once_cell", @@ -2965,17 +2965,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "num-derive" version = "0.4.0" @@ -3268,9 +3257,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pgp" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a79d6411154d1a9908e7a2c4bac60a5742f6125823c2c30780c7039aef02f0" +checksum = "27e1f8e085bfa9b85763fe3ddaacbe90a09cd847b3833129153a6cb063bbe132" dependencies = [ "aes", "base64 0.21.2", @@ -3286,6 +3275,7 @@ dependencies = [ "chrono", "cipher", "crc24", + "curve25519-dalek 4.0.0-rc.3", "derive_builder", "des", "digest 0.10.7", @@ -3299,13 +3289,13 @@ dependencies = [ "md-5", "nom", "num-bigint-dig", - "num-derive 0.3.3", + "num-derive", "num-traits", "p256 0.13.2", "p384 0.13.0", "rand 0.8.5", "ripemd", - "rsa 0.9.0-pre.2", + "rsa 0.9.2", "sha1", "sha2 0.10.7", "sha3", @@ -3965,9 +3955,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.0-pre.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65db0998ad35adcaca498b7358992e088ee16cc783fe6fb899da203e113a63e5" +checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" dependencies = [ "byteorder", "const-oid", @@ -3980,6 +3970,7 @@ dependencies = [ "pkcs8 0.10.2", "rand_core 0.6.4", "signature 2.1.0", + "spki 0.7.2", "subtle", "zeroize", ] @@ -5702,12 +5693,13 @@ dependencies = [ [[package]] name = "x25519-dalek" -version = "2.0.0-pre.1" +version = "2.0.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5da623d8af10a62342bcbbb230e33e58a63255a58012f8653c578e54bab48df" +checksum = "ec7fae07da688e17059d5886712c933bb0520f15eff2e09cfa18e30968f4e63a" dependencies = [ - "curve25519-dalek 3.2.0", + "curve25519-dalek 4.0.0-rc.3", "rand_core 0.6.4", + "serde", "zeroize", ] diff --git a/deny.toml b/deny.toml index b9c4b7432..8f5b21649 100644 --- a/deny.toml +++ b/deny.toml @@ -29,7 +29,6 @@ skip = [ { name = "hashbrown", version = "<0.14.0" }, { name = "idna", version = "<0.3" }, { name = "indexmap", version = "<2.0.0" }, - { name = "num-derive", version = "0.3.3" }, { name = "pem-rfc7468", version = "0.6.0" }, { name = "pkcs8", version = "0.9.0" }, { name = "quick-error", version = "<2.0" }, From d797de7a8d1f83d1b311b08e70157e4db586b65e Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 24 Jul 2023 16:34:24 +0000 Subject: [PATCH 020/102] refactor: use slices and vectors instead of Keyring wrapper This change removes all traces of dc_keyring_t, which was a C implementation of dynamically sized array. --- deltachat-ffi/Doxyfile | 2 +- src/decrypt.rs | 19 +++++---- src/e2ee.rs | 7 ++-- src/keyring.rs | 91 ------------------------------------------ src/lib.rs | 1 - src/mimeparser.rs | 6 +-- src/pgp.rs | 76 +++++++++++------------------------ 7 files changed, 40 insertions(+), 162 deletions(-) delete mode 100644 src/keyring.rs diff --git a/deltachat-ffi/Doxyfile b/deltachat-ffi/Doxyfile index 03365989d..5c60f15e3 100644 --- a/deltachat-ffi/Doxyfile +++ b/deltachat-ffi/Doxyfile @@ -846,7 +846,7 @@ EXCLUDE_PATTERNS = # exclude all test directories use the pattern */test/* ###################################################### -EXCLUDE_SYMBOLS = dc_aheader_t dc_apeerstate_t dc_e2ee_helper_t dc_imap_t dc_job*_t dc_key_t dc_keyring_t dc_loginparam_t dc_mime*_t +EXCLUDE_SYMBOLS = dc_aheader_t dc_apeerstate_t dc_e2ee_helper_t dc_imap_t dc_job*_t dc_key_t dc_loginparam_t dc_mime*_t EXCLUDE_SYMBOLS += dc_saxparser_t dc_simplify_t dc_smtp_t dc_sqlite3_t dc_strbuilder_t dc_param_t dc_hash_t dc_hashelem_t EXCLUDE_SYMBOLS += _dc_* jsmn* ###################################################### diff --git a/src/decrypt.rs b/src/decrypt.rs index e84e87ce9..009be6161 100644 --- a/src/decrypt.rs +++ b/src/decrypt.rs @@ -13,7 +13,6 @@ use crate::contact::addr_cmp; use crate::context::Context; use crate::headerdef::{HeaderDef, HeaderDefMap}; use crate::key::{DcKey, Fingerprint, SignedPublicKey, SignedSecretKey}; -use crate::keyring::Keyring; use crate::peerstate::Peerstate; use crate::pgp; @@ -26,8 +25,8 @@ use crate::pgp; pub fn try_decrypt( context: &Context, mail: &ParsedMail<'_>, - private_keyring: &Keyring, - public_keyring_for_validate: &Keyring, + private_keyring: &[SignedSecretKey], + public_keyring_for_validate: &[SignedPublicKey], ) -> Result, HashSet)>> { let encrypted_data_part = match get_autocrypt_mime(mail) .or_else(|| get_mixed_up_mime(mail)) @@ -211,8 +210,8 @@ fn get_autocrypt_mime<'a, 'b>(mail: &'a ParsedMail<'b>) -> Option<&'a ParsedMail /// Returns Ok(None) if nothing encrypted was found. fn decrypt_part( mail: &ParsedMail<'_>, - private_keyring: &Keyring, - public_keyring_for_validate: &Keyring, + private_keyring: &[SignedSecretKey], + public_keyring_for_validate: &[SignedPublicKey], ) -> Result, HashSet)>> { let data = mail.get_body_raw()?; @@ -247,7 +246,7 @@ fn has_decrypted_pgp_armor(input: &[u8]) -> bool { /// Returns None if the message is not Multipart/Signed or doesn't contain necessary parts. pub(crate) fn validate_detached_signature<'a, 'b>( mail: &'a ParsedMail<'b>, - public_keyring_for_validate: &Keyring, + public_keyring_for_validate: &[SignedPublicKey], ) -> Option<(&'a ParsedMail<'b>, HashSet)> { if mail.ctype.mimetype != "multipart/signed" { return None; @@ -267,13 +266,13 @@ pub(crate) fn validate_detached_signature<'a, 'b>( } } -pub(crate) fn keyring_from_peerstate(peerstate: Option<&Peerstate>) -> Keyring { - let mut public_keyring_for_validate: Keyring = Keyring::new(); +pub(crate) fn keyring_from_peerstate(peerstate: Option<&Peerstate>) -> Vec { + let mut public_keyring_for_validate = Vec::new(); if let Some(peerstate) = peerstate { if let Some(key) = &peerstate.public_key { - public_keyring_for_validate.add(key.clone()); + public_keyring_for_validate.push(key.clone()); } else if let Some(key) = &peerstate.gossip_key { - public_keyring_for_validate.add(key.clone()); + public_keyring_for_validate.push(key.clone()); } } public_keyring_for_validate diff --git a/src/e2ee.rs b/src/e2ee.rs index b870f89fe..160609348 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -7,7 +7,6 @@ use crate::aheader::{Aheader, EncryptPreference}; use crate::config::Config; use crate::context::Context; use crate::key::{DcKey, SignedPublicKey, SignedSecretKey}; -use crate::keyring::Keyring; use crate::peerstate::{Peerstate, PeerstateVerifiedStatus}; use crate::pgp; @@ -104,7 +103,7 @@ impl EncryptHelper { mail_to_encrypt: lettre_email::PartBuilder, peerstates: Vec<(Option, &str)>, ) -> Result { - let mut keyring: Keyring = Keyring::new(); + let mut keyring: Vec = Vec::new(); for (peerstate, addr) in peerstates .into_iter() @@ -113,9 +112,9 @@ impl EncryptHelper { let key = peerstate .take_key(min_verified) .with_context(|| format!("proper enc-key for {addr} missing, cannot encrypt"))?; - keyring.add(key); + keyring.push(key); } - keyring.add(self.public_key.clone()); + keyring.push(self.public_key.clone()); let sign_key = SignedSecretKey::load_self(context).await?; let raw_message = mail_to_encrypt.build().as_string().into_bytes(); diff --git a/src/keyring.rs b/src/keyring.rs deleted file mode 100644 index fa5e9b5f4..000000000 --- a/src/keyring.rs +++ /dev/null @@ -1,91 +0,0 @@ -//! Keyring to perform rpgp operations with. - -use anyhow::Result; - -use crate::context::Context; -use crate::key::DcKey; - -/// An in-memory keyring. -/// -/// Instances are usually constructed just for the rpgp operation and -/// short-lived. -#[derive(Clone, Debug, Default)] -pub struct Keyring -where - T: DcKey, -{ - keys: Vec, -} - -impl Keyring -where - T: DcKey, -{ - /// New empty keyring. - pub fn new() -> Keyring { - Keyring { keys: Vec::new() } - } - - /// Create a new keyring with the the user's secret key loaded. - pub async fn new_self(context: &Context) -> Result> { - let mut keyring: Keyring = Keyring::new(); - keyring.load_self(context).await?; - Ok(keyring) - } - - /// Load the user's key into the keyring. - pub async fn load_self(&mut self, context: &Context) -> Result<()> { - self.add(T::load_self(context).await?); - Ok(()) - } - - /// Add a key to the keyring. - pub fn add(&mut self, key: T) { - self.keys.push(key); - } - - pub fn len(&self) -> usize { - self.keys.len() - } - - pub fn is_empty(&self) -> bool { - self.keys.is_empty() - } - - /// A vector with reference to all the keys in the keyring. - pub fn keys(&self) -> &[T] { - &self.keys - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::key::{SignedPublicKey, SignedSecretKey}; - use crate::test_utils::{alice_keypair, TestContext}; - - #[test] - fn test_keyring_add_keys() { - let alice = alice_keypair(); - let mut pub_ring: Keyring = Keyring::new(); - pub_ring.add(alice.public.clone()); - assert_eq!(pub_ring.keys(), [alice.public]); - - let mut sec_ring: Keyring = Keyring::new(); - sec_ring.add(alice.secret.clone()); - assert_eq!(sec_ring.keys(), [alice.secret]); - } - - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - async fn test_keyring_load_self() { - // new_self() implies load_self() - let t = TestContext::new_alice().await; - let alice = alice_keypair(); - - let pub_ring: Keyring = Keyring::new_self(&t).await.unwrap(); - assert_eq!(pub_ring.keys(), [alice.public]); - - let sec_ring: Keyring = Keyring::new_self(&t).await.unwrap(); - assert_eq!(sec_ring.keys(), [alice.secret]); - } -} diff --git a/src/lib.rs b/src/lib.rs index b1230e2d6..316507333 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,7 +70,6 @@ mod scheduler; #[macro_use] mod job; pub mod key; -mod keyring; pub mod location; mod login_param; pub mod message; diff --git a/src/mimeparser.rs b/src/mimeparser.rs index a0cccd1b2..bd0879398 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -28,7 +28,6 @@ use crate::dehtml::dehtml; use crate::events::EventType; use crate::headerdef::{HeaderDef, HeaderDefMap}; use crate::key::{DcKey, Fingerprint, SignedPublicKey, SignedSecretKey}; -use crate::keyring::Keyring; use crate::message::{self, set_msg_failed, update_msg_state, MessageState, MsgId, Viewtype}; use crate::param::{Param, Params}; use crate::peerstate::Peerstate; @@ -276,9 +275,10 @@ impl MimeMessage { headers.remove("chat-verified"); let from = from.context("No from in message")?; - let private_keyring: Keyring = Keyring::new_self(context) + let private_keyring = vec![SignedSecretKey::load_self(context) .await - .context("failed to get own keyring")?; + .context("Failed to get own key")?]; + let mut decryption_info = prepare_decryption(context, &mail, &from.addr, message_time).await?; diff --git a/src/pgp.rs b/src/pgp.rs index 43ea19f9a..2eaf7e826 100644 --- a/src/pgp.rs +++ b/src/pgp.rs @@ -20,7 +20,6 @@ use tokio::runtime::Handle; use crate::constants::KeyGenType; use crate::key::{DcKey, Fingerprint}; -use crate::keyring::Keyring; use crate::tools::EmailAddress; #[allow(missing_docs)] @@ -229,7 +228,7 @@ fn select_pk_for_encryption(key: &SignedPublicKey) -> Option, + public_keys_for_encryption: Vec, private_key_for_signing: Option, ) -> Result { let lit_msg = Message::new_literal_bytes("", plain); @@ -237,7 +236,6 @@ pub async fn pk_encrypt( Handle::current() .spawn_blocking(move || { let pkeys: Vec = public_keys_for_encryption - .keys() .iter() .filter_map(select_pk_for_encryption) .collect(); @@ -288,15 +286,15 @@ pub fn pk_calc_signature( #[allow(clippy::implicit_hasher)] pub fn pk_decrypt( ctext: Vec, - private_keys_for_decryption: &Keyring, - public_keys_for_validation: &Keyring, + private_keys_for_decryption: &[SignedSecretKey], + public_keys_for_validation: &[SignedPublicKey], ) -> Result<(Vec, HashSet)> { let mut ret_signature_fingerprints: HashSet = Default::default(); let cursor = Cursor::new(ctext); let (msg, _) = Message::from_armor_single(cursor)?; - let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption.keys().iter().collect(); + let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption.iter().collect(); let (decryptor, _) = msg.decrypt(|| "".into(), &skeys[..])?; let msgs = decryptor.collect::>>()?; @@ -311,20 +309,13 @@ pub fn pk_decrypt( None => bail!("The decrypted message is empty"), }; - if !public_keys_for_validation.is_empty() { - let pkeys = public_keys_for_validation.keys(); - - let mut fingerprints: Vec = Vec::new(); - if let signed_msg @ pgp::composed::Message::Signed { .. } = msg { - for pkey in pkeys { - if signed_msg.verify(&pkey.primary_key).is_ok() { - let fp = DcKey::fingerprint(pkey); - fingerprints.push(fp); - } + if let signed_msg @ pgp::composed::Message::Signed { .. } = msg { + for pkey in public_keys_for_validation { + if signed_msg.verify(&pkey.primary_key).is_ok() { + let fp = DcKey::fingerprint(pkey); + ret_signature_fingerprints.insert(fp); } } - - ret_signature_fingerprints.extend(fingerprints); } Ok((content, ret_signature_fingerprints)) } else { @@ -336,12 +327,11 @@ pub fn pk_decrypt( pub fn pk_validate( content: &[u8], signature: &[u8], - public_keys_for_validation: &Keyring, + public_keys_for_validation: &[SignedPublicKey], ) -> Result> { let mut ret: HashSet = Default::default(); let standalone_signature = StandaloneSignature::from_armor_single(Cursor::new(signature))?.0; - let pkeys = public_keys_for_validation.keys(); // Remove trailing CRLF before the delimiter. // According to RFC 3156 it is considered to be part of the MIME delimiter for the purpose of @@ -350,7 +340,7 @@ pub fn pk_validate( .get(..content.len().saturating_sub(2)) .context("index is out of range")?; - for pkey in pkeys { + for pkey in public_keys_for_validation { if standalone_signature.verify(pkey, content).is_ok() { let fp = DcKey::fingerprint(pkey); ret.insert(fp); @@ -485,9 +475,7 @@ mod tests { async fn ctext_signed() -> &'static String { CTEXT_SIGNED .get_or_init(|| async { - let mut keyring = Keyring::new(); - keyring.add(KEYS.alice_public.clone()); - keyring.add(KEYS.bob_public.clone()); + let keyring = vec![KEYS.alice_public.clone(), KEYS.bob_public.clone()]; pk_encrypt(CLEARTEXT, keyring, Some(KEYS.alice_secret.clone())) .await @@ -500,9 +488,7 @@ mod tests { async fn ctext_unsigned() -> &'static String { CTEXT_UNSIGNED .get_or_init(|| async { - let mut keyring = Keyring::new(); - keyring.add(KEYS.alice_public.clone()); - keyring.add(KEYS.bob_public.clone()); + let keyring = vec![KEYS.alice_public.clone(), KEYS.bob_public.clone()]; pk_encrypt(CLEARTEXT, keyring, None).await.unwrap() }) .await @@ -527,10 +513,8 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decrypt_singed() { // Check decrypting as Alice - let mut decrypt_keyring: Keyring = Keyring::new(); - decrypt_keyring.add(KEYS.alice_secret.clone()); - let mut sig_check_keyring: Keyring = Keyring::new(); - sig_check_keyring.add(KEYS.alice_public.clone()); + let decrypt_keyring = vec![KEYS.alice_secret.clone()]; + let sig_check_keyring = vec![KEYS.alice_public.clone()]; let (plain, valid_signatures) = pk_decrypt( ctext_signed().await.as_bytes().to_vec(), &decrypt_keyring, @@ -541,10 +525,8 @@ mod tests { assert_eq!(valid_signatures.len(), 1); // Check decrypting as Bob - let mut decrypt_keyring = Keyring::new(); - decrypt_keyring.add(KEYS.bob_secret.clone()); - let mut sig_check_keyring = Keyring::new(); - sig_check_keyring.add(KEYS.alice_public.clone()); + let decrypt_keyring = vec![KEYS.bob_secret.clone()]; + let sig_check_keyring = vec![KEYS.alice_public.clone()]; let (plain, valid_signatures) = pk_decrypt( ctext_signed().await.as_bytes().to_vec(), &decrypt_keyring, @@ -557,15 +539,9 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decrypt_no_sig_check() { - let mut keyring = Keyring::new(); - keyring.add(KEYS.alice_secret.clone()); - let empty_keyring = Keyring::new(); - let (plain, valid_signatures) = pk_decrypt( - ctext_signed().await.as_bytes().to_vec(), - &keyring, - &empty_keyring, - ) - .unwrap(); + let keyring = vec![KEYS.alice_secret.clone()]; + let (plain, valid_signatures) = + pk_decrypt(ctext_signed().await.as_bytes().to_vec(), &keyring, &[]).unwrap(); assert_eq!(plain, CLEARTEXT); assert_eq!(valid_signatures.len(), 0); } @@ -573,10 +549,8 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decrypt_signed_no_key() { // The validation does not have the public key of the signer. - let mut decrypt_keyring = Keyring::new(); - decrypt_keyring.add(KEYS.bob_secret.clone()); - let mut sig_check_keyring = Keyring::new(); - sig_check_keyring.add(KEYS.bob_public.clone()); + let decrypt_keyring = vec![KEYS.bob_secret.clone()]; + let sig_check_keyring = vec![KEYS.bob_public.clone()]; let (plain, valid_signatures) = pk_decrypt( ctext_signed().await.as_bytes().to_vec(), &decrypt_keyring, @@ -589,13 +563,11 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decrypt_unsigned() { - let mut decrypt_keyring = Keyring::new(); - decrypt_keyring.add(KEYS.bob_secret.clone()); - let sig_check_keyring = Keyring::new(); + let decrypt_keyring = vec![KEYS.bob_secret.clone()]; let (plain, valid_signatures) = pk_decrypt( ctext_unsigned().await.as_bytes().to_vec(), &decrypt_keyring, - &sig_check_keyring, + &[], ) .unwrap(); assert_eq!(plain, CLEARTEXT); From 170968dfc28251925613af4de1b36b6bec4b851a Mon Sep 17 00:00:00 2001 From: Hocuri Date: Tue, 25 Jul 2023 16:50:10 +0200 Subject: [PATCH 021/102] Update README.md --- README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9dec8d468..96ff5b485 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,16 @@ -# Delta Chat Rust +

+ Delta Chat Logo +

-> Deltachat-core written in Rust +

+ + Rust CI + +

-[![Rust CI](https://github.com/deltachat/deltachat-core-rust/actions/workflows/ci.yml/badge.svg)](https://github.com/deltachat/deltachat-core-rust/actions/workflows/ci.yml) +

+The core library for Delta Chat, written in Rust +

## Installing Rust and Cargo From 6d51d19f0199e541846ef99009754d75728cc45a Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 24 Jul 2023 18:29:03 +0000 Subject: [PATCH 022/102] refactor(e2ee): do not return anything from ensure_secret_key_exists() The return value was never used. --- src/e2ee.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/e2ee.rs b/src/e2ee.rs index 160609348..2addaf56d 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -144,14 +144,10 @@ impl EncryptHelper { /// sent 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. // TODO, remove this once deltachat::key::Key no longer exists. -pub async fn ensure_secret_key_exists(context: &Context) -> Result { - let self_addr = context.get_primary_self_addr().await?; +pub async fn ensure_secret_key_exists(context: &Context) -> Result<()> { SignedPublicKey::load_self(context).await?; - Ok(self_addr) + Ok(()) } #[cfg(test)] @@ -168,10 +164,7 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_prexisting() { let t = TestContext::new_alice().await; - assert_eq!( - ensure_secret_key_exists(&t).await.unwrap(), - "alice@example.org" - ); + assert!(ensure_secret_key_exists(&t).await.is_ok()); } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] From f27d304f3b12aabb1a28fd311819e9fe54763351 Mon Sep 17 00:00:00 2001 From: iequidoo Date: Mon, 10 Apr 2023 11:33:34 -0400 Subject: [PATCH 023/102] feat!: Add lockfile to account manager (#4310) Opening the same account (context) from multiple processes is dangerous, can result in duplicate downloads of the same message etc. Same for account manager, attempts to modify the same accounts.toml even if done atomically with may result in corrupted files as atomic replacement procedure does not expect that multiple processes may write to the same temporary file. accounts.toml cannot be used as a lockfile because it is replaced during atomic update. Therefore, a new file next to accounts.toml is needed to prevent starting second account manager in the same directory. But iOS needs to be able to open accounts from multiple processes at the same time. This is required as the "share-to-DC extension" is a separate process by iOS design -- this process may or may not be started while the main app is running. Accounts are not altered however by this extension, so let's add to the `Accounts::new()` constructor an `rdwr` parameter which allows to read the accounts config w/o locking the lockfile. --- Cargo.lock | 1 + Cargo.toml | 1 + benches/create_account.rs | 3 +- deltachat-ffi/deltachat.h | 5 +- deltachat-ffi/src/lib.rs | 8 +- deltachat-jsonrpc/src/lib.rs | 6 +- deltachat-jsonrpc/src/webserver.rs | 3 +- deltachat-rpc-server/src/main.rs | 3 +- node/lib/deltachat.ts | 7 +- node/src/module.c | 6 +- python/tests/test_4_lowlevel.py | 3 +- src/accounts.rs | 168 +++++++++++++++++++++++------ 12 files changed, 165 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 27ea5bd48..3807895c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1132,6 +1132,7 @@ dependencies = [ "encoded-words", "escaper", "fast-socks5", + "fd-lock", "format-flowed", "futures", "futures-lite", diff --git a/Cargo.toml b/Cargo.toml index 57efe378f..5625f62bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,7 @@ email = { git = "https://github.com/deltachat/rust-email", branch = "master" } encoded-words = { git = "https://github.com/async-email/encoded-words", branch = "master" } escaper = "0.1" fast-socks5 = "0.8" +fd-lock = "3.0.11" futures = "0.3" futures-lite = "1.13.0" hex = "0.4.0" diff --git a/benches/create_account.rs b/benches/create_account.rs index 5e1ae8561..c487004ac 100644 --- a/benches/create_account.rs +++ b/benches/create_account.rs @@ -8,7 +8,8 @@ async fn create_accounts(n: u32) { let dir = tempdir().unwrap(); let p: PathBuf = dir.path().join("accounts"); - let mut accounts = Accounts::new(p.clone()).await.unwrap(); + let writable = true; + let mut accounts = Accounts::new(p.clone(), writable).await.unwrap(); for expected_id in 2..n { let id = accounts.add_account().await.unwrap(); diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index b55b9df30..ce8a9e91f 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -2915,12 +2915,15 @@ int dc_receive_backup (dc_context_t* context, const char* qr); * @param dir The directory to create the context-databases in. * If the directory does not exist, * dc_accounts_new() will try to create it. + * @param writable Whether the returned account manager is writable, i.e. calling these functions on + * it is possible: dc_accounts_add_account(), dc_accounts_add_closed_account(), + * dc_accounts_migrate_account(), dc_accounts_remove_account(), dc_accounts_select_account(). * @return An account manager object. * The object must be passed to the other account manager functions * and must be freed using dc_accounts_unref() after usage. * On errors, NULL is returned. */ -dc_accounts_t* dc_accounts_new (const char* os_name, const char* dir); +dc_accounts_t* dc_accounts_new (const char* dir, int writable); /** diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index b97a12d5a..3efb48c9c 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -4676,17 +4676,17 @@ pub type dc_accounts_t = AccountsWrapper; #[no_mangle] pub unsafe extern "C" fn dc_accounts_new( - _os_name: *const libc::c_char, - dbfile: *const libc::c_char, + dir: *const libc::c_char, + writable: libc::c_int, ) -> *mut dc_accounts_t { setup_panic!(); - if dbfile.is_null() { + if dir.is_null() { eprintln!("ignoring careless call to dc_accounts_new()"); return ptr::null_mut(); } - let accs = block_on(Accounts::new(as_path(dbfile).into())); + let accs = block_on(Accounts::new(as_path(dir).into(), writable != 0)); match accs { Ok(accs) => Box::into_raw(Box::new(AccountsWrapper::new(accs))), diff --git a/deltachat-jsonrpc/src/lib.rs b/deltachat-jsonrpc/src/lib.rs index 16592bd88..10ec39ea4 100644 --- a/deltachat-jsonrpc/src/lib.rs +++ b/deltachat-jsonrpc/src/lib.rs @@ -13,7 +13,8 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn basic_json_rpc_functionality() -> anyhow::Result<()> { let tmp_dir = TempDir::new().unwrap().path().into(); - let accounts = Accounts::new(tmp_dir).await?; + let writable = true; + let accounts = Accounts::new(tmp_dir, writable).await?; let api = CommandApi::new(accounts); let (sender, mut receiver) = unbounded::(); @@ -54,7 +55,8 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn test_batch_set_config() -> anyhow::Result<()> { let tmp_dir = TempDir::new().unwrap().path().into(); - let accounts = Accounts::new(tmp_dir).await?; + let writable = true; + let accounts = Accounts::new(tmp_dir, writable).await?; let api = CommandApi::new(accounts); let (sender, mut receiver) = unbounded::(); diff --git a/deltachat-jsonrpc/src/webserver.rs b/deltachat-jsonrpc/src/webserver.rs index df8f92135..f4b6f38af 100644 --- a/deltachat-jsonrpc/src/webserver.rs +++ b/deltachat-jsonrpc/src/webserver.rs @@ -19,7 +19,8 @@ async fn main() -> Result<(), std::io::Error> { .map(|port| port.parse::().expect("DC_PORT must be a number")) .unwrap_or(DEFAULT_PORT); log::info!("Starting with accounts directory `{path}`."); - let accounts = Accounts::new(PathBuf::from(&path)).await.unwrap(); + let writable = true; + let accounts = Accounts::new(PathBuf::from(&path), writable).await.unwrap(); let state = CommandApi::new(accounts); let app = Router::new() diff --git a/deltachat-rpc-server/src/main.rs b/deltachat-rpc-server/src/main.rs index e3d0b0b20..1a3049f85 100644 --- a/deltachat-rpc-server/src/main.rs +++ b/deltachat-rpc-server/src/main.rs @@ -56,7 +56,8 @@ async fn main_impl() -> Result<()> { let path = std::env::var("DC_ACCOUNTS_PATH").unwrap_or_else(|_| "accounts".to_string()); log::info!("Starting with accounts directory `{}`.", path); - let accounts = Accounts::new(PathBuf::from(&path)).await?; + let writable = true; + let accounts = Accounts::new(PathBuf::from(&path), writable).await?; log::info!("Creating JSON-RPC API."); let accounts = Arc::new(RwLock::new(accounts)); diff --git a/node/lib/deltachat.ts b/node/lib/deltachat.ts index 2526b9378..dbf002e46 100644 --- a/node/lib/deltachat.ts +++ b/node/lib/deltachat.ts @@ -21,12 +21,15 @@ export class AccountManager extends EventEmitter { accountDir: string jsonRpcStarted = false - constructor(cwd: string, os = 'deltachat-node') { + constructor(cwd: string, writable = true) { super() debug('DeltaChat constructor') this.accountDir = cwd - this.dcn_accounts = binding.dcn_accounts_new(os, this.accountDir) + this.dcn_accounts = binding.dcn_accounts_new( + this.accountDir, + writable ? 1 : 0 + ) } getAllAccountIds() { diff --git a/node/src/module.c b/node/src/module.c index de24e2c90..5c675020e 100644 --- a/node/src/module.c +++ b/node/src/module.c @@ -2903,8 +2903,8 @@ NAPI_METHOD(dcn_msg_get_webxdc_blob){ NAPI_METHOD(dcn_accounts_new) { NAPI_ARGV(2); - NAPI_ARGV_UTF8_MALLOC(os_name, 0); - NAPI_ARGV_UTF8_MALLOC(dir, 1); + NAPI_ARGV_UTF8_MALLOC(dir, 0); + NAPI_ARGV_INT32(writable, 1); TRACE("calling.."); dcn_accounts_t* dcn_accounts = calloc(1, sizeof(dcn_accounts_t)); @@ -2913,7 +2913,7 @@ NAPI_METHOD(dcn_accounts_new) { } - dcn_accounts->dc_accounts = dc_accounts_new(os_name, dir); + dcn_accounts->dc_accounts = dc_accounts_new(dir, writable); napi_value result; NAPI_STATUS_THROWS(napi_create_external(env, dcn_accounts, diff --git a/python/tests/test_4_lowlevel.py b/python/tests/test_4_lowlevel.py index 1fd961bca..5f1ec1003 100644 --- a/python/tests/test_4_lowlevel.py +++ b/python/tests/test_4_lowlevel.py @@ -221,8 +221,9 @@ def test_logged_ac_process_ffi_failure(acfactory): def test_jsonrpc_blocking_call(tmp_path): accounts_fname = tmp_path / "accounts" + writable = True accounts = ffi.gc( - lib.dc_accounts_new(ffi.NULL, str(accounts_fname).encode("ascii")), + lib.dc_accounts_new(str(accounts_fname).encode("ascii"), writable), lib.dc_accounts_unref, ) jsonrpc = ffi.gc(lib.dc_jsonrpc_init(accounts), lib.dc_jsonrpc_unref) diff --git a/src/accounts.rs b/src/accounts.rs index 9c214b371..8ae05491a 100644 --- a/src/accounts.rs +++ b/src/accounts.rs @@ -7,6 +7,9 @@ use anyhow::{ensure, Context as _, Result}; use serde::{Deserialize, Serialize}; use tokio::fs; use tokio::io::AsyncWriteExt; +use tokio::sync::oneshot; +use tokio::task::JoinHandle; +use tokio::time::{sleep, Duration}; use uuid::Uuid; use crate::context::Context; @@ -33,16 +36,16 @@ pub struct Accounts { impl Accounts { /// Loads or creates an accounts folder at the given `dir`. - pub async fn new(dir: PathBuf) -> Result { - if !dir.exists() { + pub async fn new(dir: PathBuf, writable: bool) -> Result { + if writable && !dir.exists() { Accounts::create(&dir).await?; } - Accounts::open(dir).await + Accounts::open(dir, writable).await } /// Creates a new default structure. - pub async fn create(dir: &Path) -> Result<()> { + async fn create(dir: &Path) -> Result<()> { fs::create_dir_all(dir) .await .context("failed to create folder")?; @@ -54,13 +57,13 @@ impl Accounts { /// Opens an existing accounts structure. Will error if the folder doesn't exist, /// no account exists and no config exists. - pub async fn open(dir: PathBuf) -> Result { + async fn open(dir: PathBuf, writable: bool) -> Result { ensure!(dir.exists(), "directory does not exist"); let config_file = dir.join(CONFIG_NAME); ensure!(config_file.exists(), "{:?} does not exist", config_file); - let config = Config::from_file(config_file) + let config = Config::from_file(config_file, writable) .await .context("failed to load accounts config")?; let events = Events::new(); @@ -298,14 +301,20 @@ impl Accounts { /// Configuration file name. pub const CONFIG_NAME: &str = "accounts.toml"; +/// Lockfile name. +pub const LOCKFILE_NAME: &str = "accounts.lock"; + /// Database file name. pub const DB_NAME: &str = "dc.db"; /// Account manager configuration file. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug)] struct Config { file: PathBuf, inner: InnerConfig, + // We lock the lockfile in the Config constructors to protect also from having multiple Config + // objects for the same config file. + lock_task: Option>>, } /// Account manager configuration file contents. @@ -319,17 +328,74 @@ struct InnerConfig { pub accounts: Vec, } +impl Drop for Config { + fn drop(&mut self) { + if let Some(lock_task) = self.lock_task.take() { + lock_task.abort(); + } + } +} + impl Config { - /// Creates a new configuration file in the given account manager directory. - pub async fn new(dir: &Path) -> Result { + /// Creates a new Config for `file`, but doesn't open/sync it. + async fn new_nosync(file: PathBuf, lock: bool) -> Result { + let dir = file.parent().context("Cannot get config file directory")?; let inner = InnerConfig { accounts: Vec::new(), selected_account: 0, next_id: 1, }; - let file = dir.join(CONFIG_NAME); - let mut cfg = Self { file, inner }; + if !lock { + let cfg = Self { + file, + inner, + lock_task: None, + }; + return Ok(cfg); + } + let lockfile = dir.join(LOCKFILE_NAME); + let mut lock = fd_lock::RwLock::new(fs::File::create(lockfile).await?); + let (locked_tx, locked_rx) = oneshot::channel(); + let lock_task: JoinHandle> = tokio::spawn(async move { + let mut timeout = Duration::from_millis(100); + let _guard = loop { + match lock.try_write() { + Ok(guard) => break Ok(guard), + Err(err) => { + if timeout.as_millis() > 1600 { + break Err(err); + } + // We need to wait for the previous lock_task to be aborted thus unlocking + // the lockfile. We don't open configs for writing often outside of the + // tests, so this adds delays to the tests, but otherwise ok. + sleep(timeout).await; + if err.kind() == std::io::ErrorKind::WouldBlock { + timeout *= 2; + } + } + } + }?; + locked_tx + .send(()) + .ok() + .context("Cannot notify about lockfile locking")?; + let (_tx, rx) = oneshot::channel(); + rx.await?; + Ok(()) + }); + let cfg = Self { + file, + inner, + lock_task: Some(lock_task), + }; + locked_rx.await?; + Ok(cfg) + } + /// Creates a new configuration file in the given account manager directory. + pub async fn new(dir: &Path) -> Result { + let lock = true; + let mut cfg = Self::new_nosync(dir.join(CONFIG_NAME), lock).await?; cfg.sync().await?; Ok(cfg) @@ -339,6 +405,11 @@ impl Config { /// Takes a mutable reference because the saved file is a part of the `Config` state. This /// protects from parallel calls resulting to a wrong file contents. async fn sync(&mut self) -> Result<()> { + ensure!(!self + .lock_task + .as_ref() + .context("Config is read-only")? + .is_finished()); let tmp_path = self.file.with_extension("toml.tmp"); let mut file = fs::File::create(&tmp_path) .await @@ -357,24 +428,28 @@ impl Config { } /// Read a configuration from the given file into memory. - pub async fn from_file(file: PathBuf) -> Result { - let dir = file.parent().context("can't get config file directory")?; - let bytes = fs::read(&file).await.context("failed to read file")?; + pub async fn from_file(file: PathBuf, writable: bool) -> Result { + let dir = file + .parent() + .context("Cannot get config file directory")? + .to_path_buf(); + let mut config = Self::new_nosync(file, writable).await?; + let bytes = fs::read(&config.file) + .await + .context("Failed to read file")?; let s = std::str::from_utf8(&bytes)?; - let mut inner: InnerConfig = toml::from_str(s).context("failed to parse config")?; + config.inner = toml::from_str(s).context("Failed to parse config")?; // Previous versions of the core stored absolute paths in account config. // Convert them to relative paths. let mut modified = false; - for account in &mut inner.accounts { - if let Ok(new_dir) = account.dir.strip_prefix(dir) { + for account in &mut config.inner.accounts { + if let Ok(new_dir) = account.dir.strip_prefix(&dir) { account.dir = new_dir.to_path_buf(); modified = true; } } - - let mut config = Self { file, inner }; - if modified { + if modified && writable { config.sync().await?; } @@ -518,26 +593,44 @@ mod tests { let p: PathBuf = dir.path().join("accounts1"); { - let mut accounts = Accounts::new(p.clone()).await.unwrap(); + let writable = true; + let mut accounts = Accounts::new(p.clone(), writable).await.unwrap(); accounts.add_account().await.unwrap(); assert_eq!(accounts.accounts.len(), 1); assert_eq!(accounts.config.get_selected_account(), 1); } - { - let accounts = Accounts::open(p).await.unwrap(); + for writable in [true, false] { + let accounts = Accounts::new(p.clone(), writable).await.unwrap(); assert_eq!(accounts.accounts.len(), 1); assert_eq!(accounts.config.get_selected_account(), 1); } } + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_account_new_open_conflict() { + let dir = tempfile::tempdir().unwrap(); + let p: PathBuf = dir.path().join("accounts"); + let writable = true; + let _accounts = Accounts::new(p.clone(), writable).await.unwrap(); + + let writable = true; + assert!(Accounts::new(p.clone(), writable).await.is_err()); + + let writable = false; + let accounts = Accounts::new(p, writable).await.unwrap(); + assert_eq!(accounts.accounts.len(), 0); + assert_eq!(accounts.config.get_selected_account(), 0); + } + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_account_new_add_remove() { let dir = tempfile::tempdir().unwrap(); let p: PathBuf = dir.path().join("accounts"); - let mut accounts = Accounts::new(p.clone()).await.unwrap(); + let writable = true; + let mut accounts = Accounts::new(p.clone(), writable).await.unwrap(); assert_eq!(accounts.accounts.len(), 0); assert_eq!(accounts.config.get_selected_account(), 0); @@ -564,7 +657,8 @@ mod tests { let dir = tempfile::tempdir()?; let p: PathBuf = dir.path().join("accounts"); - let mut accounts = Accounts::new(p.clone()).await?; + let writable = true; + let mut accounts = Accounts::new(p.clone(), writable).await?; assert!(accounts.get_selected_account().is_none()); assert_eq!(accounts.config.get_selected_account(), 0); @@ -585,7 +679,8 @@ mod tests { let dir = tempfile::tempdir().unwrap(); let p: PathBuf = dir.path().join("accounts"); - let mut accounts = Accounts::new(p.clone()).await.unwrap(); + let writable = true; + let mut accounts = Accounts::new(p.clone(), writable).await.unwrap(); assert_eq!(accounts.accounts.len(), 0); assert_eq!(accounts.config.get_selected_account(), 0); @@ -622,7 +717,8 @@ mod tests { let dir = tempfile::tempdir().unwrap(); let p: PathBuf = dir.path().join("accounts"); - let mut accounts = Accounts::new(p.clone()).await.unwrap(); + let writable = true; + let mut accounts = Accounts::new(p.clone(), writable).await.unwrap(); for expected_id in 1..10 { let id = accounts.add_account().await.unwrap(); @@ -642,7 +738,8 @@ mod tests { let dummy_accounts = 10; let (id0, id1, id2) = { - let mut accounts = Accounts::new(p.clone()).await?; + let writable = true; + let mut accounts = Accounts::new(p.clone(), writable).await?; accounts.add_account().await?; let ids = accounts.get_all(); assert_eq!(ids.len(), 1); @@ -677,7 +774,8 @@ mod tests { assert!(id2 > id1 + dummy_accounts); let (id0_reopened, id1_reopened, id2_reopened) = { - let accounts = Accounts::new(p.clone()).await?; + let writable = false; + let accounts = Accounts::new(p.clone(), writable).await?; let ctx = accounts.get_selected_account().unwrap(); assert_eq!( ctx.get_config(crate::config::Config::Addr).await?, @@ -722,7 +820,8 @@ mod tests { let dir = tempfile::tempdir().unwrap(); let p: PathBuf = dir.path().join("accounts"); - let accounts = Accounts::new(p.clone()).await?; + let writable = true; + let accounts = Accounts::new(p.clone(), writable).await?; // Make sure there are no accounts. assert_eq!(accounts.accounts.len(), 0); @@ -748,7 +847,8 @@ mod tests { let dir = tempfile::tempdir().context("failed to create tempdir")?; let p: PathBuf = dir.path().join("accounts"); - let mut accounts = Accounts::new(p.clone()) + let writable = true; + let mut accounts = Accounts::new(p.clone(), writable) .await .context("failed to create accounts manager")?; @@ -768,7 +868,8 @@ mod tests { assert!(passphrase_set_success); drop(accounts); - let accounts = Accounts::new(p.clone()) + let writable = false; + let accounts = Accounts::new(p.clone(), writable) .await .context("failed to create second accounts manager")?; let account = accounts @@ -792,7 +893,8 @@ mod tests { let dir = tempfile::tempdir().unwrap(); let p: PathBuf = dir.path().join("accounts"); - let mut accounts = Accounts::new(p.clone()).await?; + let writable = true; + let mut accounts = Accounts::new(p.clone(), writable).await?; accounts.add_account().await?; accounts.add_account().await?; From c55a3d387308d697bf9dd88b319d4b24ee6429cc Mon Sep 17 00:00:00 2001 From: link2xt Date: Thu, 27 Jul 2023 17:47:30 +0000 Subject: [PATCH 024/102] refactor: flatten and simplify imports --- deltachat-ffi/src/lib.rs | 3 ++- src/chat.rs | 3 ++- src/debug_logging.rs | 18 ++++++++---------- src/html.rs | 4 ++-- src/key.rs | 3 +-- src/login_param.rs | 3 ++- src/qr.rs | 3 ++- src/qr_code_generator.rs | 20 +++++++++----------- src/smtp.rs | 3 ++- src/test_utils.rs | 11 ++++++----- src/webxdc.rs | 4 ++-- 11 files changed, 38 insertions(+), 37 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 3efb48c9c..bee0167d8 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -32,6 +32,7 @@ use deltachat::imex::BackupProvider; use deltachat::key::DcKey; use deltachat::message::MsgId; use deltachat::net::read_url_blob; +use deltachat::pgp::KeyPair; use deltachat::qr_code_generator::{generate_backup_qr, get_securejoin_qr_svg}; use deltachat::reaction::{get_msg_reactions, send_reaction, Reactions}; use deltachat::stock_str::StockMessage; @@ -799,7 +800,7 @@ pub unsafe extern "C" fn dc_preconfigure_keypair( let addr = tools::EmailAddress::new(&to_string_lossy(addr))?; let public = key::SignedPublicKey::from_asc(&to_string_lossy(public_data))?.0; let secret = key::SignedSecretKey::from_asc(&to_string_lossy(secret_data))?.0; - let keypair = key::KeyPair { + let keypair = KeyPair { addr, public, secret, diff --git a/src/chat.rs b/src/chat.rs index 6e44cb8ff..fa402d948 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -25,6 +25,7 @@ use crate::debug_logging::maybe_set_logging_xdc; use crate::ephemeral::Timer as EphemeralTimer; use crate::events::EventType; use crate::html::new_html_mimepart; +use crate::location; use crate::message::{self, Message, MessageState, MsgId, Viewtype}; use crate::mimefactory::MimeFactory; use crate::mimeparser::SystemMessage; @@ -33,6 +34,7 @@ use crate::peerstate::{Peerstate, PeerstateVerifiedStatus}; use crate::receive_imf::ReceivedMsg; use crate::scheduler::InterruptInfo; use crate::smtp::send_msg_to_smtp; +use crate::sql; use crate::stock_str; use crate::tools::{ buf_compress, create_id, create_outgoing_rfc724_mid, create_smeared_timestamp, @@ -40,7 +42,6 @@ use crate::tools::{ strip_rtlo_characters, time, IsNoneOrEmpty, }; use crate::webxdc::WEBXDC_SUFFIX; -use crate::{location, sql}; /// An chat item, such as a message or a marker. #[derive(Debug, Copy, Clone, PartialEq, Eq)] diff --git a/src/debug_logging.rs b/src/debug_logging.rs index 7b343a35f..d9a67473e 100644 --- a/src/debug_logging.rs +++ b/src/debug_logging.rs @@ -1,14 +1,12 @@ //! Forward log messages to logging webxdc -use crate::{ - chat::ChatId, - config::Config, - context::Context, - message::{Message, MsgId, Viewtype}, - param::Param, - tools::time, - webxdc::StatusUpdateItem, - EventType, -}; +use crate::chat::ChatId; +use crate::config::Config; +use crate::context::Context; +use crate::events::EventType; +use crate::message::{Message, MsgId, Viewtype}; +use crate::param::Param; +use crate::tools::time; +use crate::webxdc::StatusUpdateItem; use async_channel::{self as channel, Receiver, Sender}; use serde_json::json; use std::path::PathBuf; diff --git a/src/html.rs b/src/html.rs index 7124c0a1a..5af221b70 100644 --- a/src/html.rs +++ b/src/html.rs @@ -17,12 +17,12 @@ use lettre_email::mime::{self, Mime}; use lettre_email::PartBuilder; use mailparse::ParsedContentType; +use crate::context::Context; use crate::headerdef::{HeaderDef, HeaderDefMap}; -use crate::message::{Message, MsgId}; +use crate::message::{self, Message, MsgId}; use crate::mimeparser::parse_message_id; use crate::param::Param::SendHtml; use crate::plaintext::PlainText; -use crate::{context::Context, message}; impl Message { /// Check if the message can be retrieved as HTML. diff --git a/src/key.rs b/src/key.rs index 2965cfb55..8f2be2d83 100644 --- a/src/key.rs +++ b/src/key.rs @@ -18,8 +18,7 @@ use tokio::runtime::Handle; use crate::config::Config; use crate::constants::KeyGenType; use crate::context::Context; -// Re-export key types -pub use crate::pgp::KeyPair; +use crate::pgp::KeyPair; use crate::tools::{time, EmailAddress}; /// Convenience trait for working with keys. diff --git a/src/login_param.rs b/src/login_param.rs index e01e43a0f..25511c419 100644 --- a/src/login_param.rs +++ b/src/login_param.rs @@ -5,9 +5,10 @@ use std::fmt; use anyhow::{ensure, Result}; use crate::constants::{DC_LP_AUTH_FLAGS, DC_LP_AUTH_NORMAL, DC_LP_AUTH_OAUTH2}; +use crate::context::Context; +use crate::provider::Socket; use crate::provider::{get_provider_by_id, Provider}; use crate::socks::Socks5Config; -use crate::{context::Context, provider::Socket}; #[derive(Copy, Clone, Debug, Display, FromPrimitive, ToPrimitive, PartialEq, Eq)] #[repr(u32)] diff --git a/src/qr.rs b/src/qr.rs index e11b74f56..7d89d3e93 100644 --- a/src/qr.rs +++ b/src/qr.rs @@ -17,11 +17,12 @@ use crate::contact::{ addr_normalize, may_be_valid_addr, Contact, ContactAddress, ContactId, Origin, }; use crate::context::Context; +use crate::events::EventType; use crate::key::Fingerprint; use crate::message::Message; use crate::peerstate::Peerstate; use crate::socks::Socks5Config; -use crate::{token, EventType}; +use crate::token; const OPENPGP4FPR_SCHEME: &str = "OPENPGP4FPR:"; // yes: uppercase const DCACCOUNT_SCHEME: &str = "DCACCOUNT:"; diff --git a/src/qr_code_generator.rs b/src/qr_code_generator.rs index 4fb9a2deb..85c3ecba6 100644 --- a/src/qr_code_generator.rs +++ b/src/qr_code_generator.rs @@ -4,17 +4,15 @@ use anyhow::Result; use base64::Engine as _; use qrcodegen::{QrCode, QrCodeEcc}; -use crate::{ - blob::BlobObject, - chat::{Chat, ChatId}, - color::color_int_to_hex_string, - config::Config, - contact::{Contact, ContactId}, - context::Context, - qr::{self, Qr}, - securejoin, - stock_str::{self, backup_transfer_qr}, -}; +use crate::blob::BlobObject; +use crate::chat::{Chat, ChatId}; +use crate::color::color_int_to_hex_string; +use crate::config::Config; +use crate::contact::{Contact, ContactId}; +use crate::context::Context; +use crate::qr::{self, Qr}; +use crate::securejoin; +use crate::stock_str::{self, backup_transfer_qr}; /// Returns SVG of the QR code to join the group or verify contact. /// diff --git a/src/smtp.rs b/src/smtp.rs index bea98ed48..d01d00926 100644 --- a/src/smtp.rs +++ b/src/smtp.rs @@ -12,6 +12,7 @@ use tokio::task; use crate::config::Config; use crate::contact::{Contact, ContactId}; +use crate::context::Context; use crate::events::EventType; use crate::login_param::{CertificateChecks, LoginParam, ServerLoginParam}; use crate::message::Message; @@ -22,9 +23,9 @@ use crate::net::session::SessionBufStream; use crate::net::tls::wrap_tls; use crate::oauth2::get_oauth2_access_token; use crate::provider::Socket; +use crate::scheduler::connectivity::ConnectivityStore; use crate::socks::Socks5Config; use crate::sql; -use crate::{context::Context, scheduler::connectivity::ConnectivityStore}; /// SMTP write and read timeout. const SMTP_TIMEOUT: Duration = Duration::from_secs(30); diff --git a/src/test_utils.rs b/src/test_utils.rs index 060256b0c..68bab184d 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -33,10 +33,11 @@ use crate::contact::{Contact, ContactAddress, ContactId, Modifier, Origin}; use crate::context::Context; use crate::e2ee::EncryptHelper; use crate::events::{Event, EventType, Events}; -use crate::key::{self, DcKey, KeyPair, KeyPairUse}; +use crate::key::{self, DcKey, KeyPairUse}; use crate::message::{update_msg_state, Message, MessageState, MsgId, Viewtype}; use crate::mimeparser::{MimeMessage, SystemMessage}; use crate::peerstate::Peerstate; +use crate::pgp::KeyPair; use crate::receive_imf::receive_imf; use crate::securejoin::{get_securejoin_qr, join_securejoin}; use crate::stock_str::StockStrings; @@ -910,7 +911,7 @@ pub fn alice_keypair() -> KeyPair { let secret = key::SignedSecretKey::from_asc(include_str!("../test-data/key/alice-secret.asc")) .unwrap() .0; - key::KeyPair { + KeyPair { addr, public, secret, @@ -928,7 +929,7 @@ pub fn bob_keypair() -> KeyPair { let secret = key::SignedSecretKey::from_asc(include_str!("../test-data/key/bob-secret.asc")) .unwrap() .0; - key::KeyPair { + KeyPair { addr, public, secret, @@ -938,7 +939,7 @@ pub fn bob_keypair() -> KeyPair { /// Load a pre-generated keypair for fiona@example.net from disk. /// /// Like [alice_keypair] but a different key and identity. -pub fn fiona_keypair() -> key::KeyPair { +pub fn fiona_keypair() -> KeyPair { let addr = EmailAddress::new("fiona@example.net").unwrap(); let public = key::SignedPublicKey::from_asc(include_str!("../test-data/key/fiona-public.asc")) .unwrap() @@ -946,7 +947,7 @@ pub fn fiona_keypair() -> key::KeyPair { let secret = key::SignedSecretKey::from_asc(include_str!("../test-data/key/fiona-secret.asc")) .unwrap() .0; - key::KeyPair { + KeyPair { addr, public, secret, diff --git a/src/webxdc.rs b/src/webxdc.rs index b2e9a9a35..44afa0143 100644 --- a/src/webxdc.rs +++ b/src/webxdc.rs @@ -12,11 +12,12 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use tokio::io::AsyncReadExt; -use crate::chat::Chat; +use crate::chat::{self, Chat}; use crate::constants::Chattype; use crate::contact::ContactId; use crate::context::Context; use crate::download::DownloadState; +use crate::events::EventType; use crate::message::{Message, MessageState, MsgId, Viewtype}; use crate::mimeparser::SystemMessage; use crate::param::Param; @@ -24,7 +25,6 @@ use crate::param::Params; use crate::scheduler::InterruptInfo; use crate::tools::strip_rtlo_characters; use crate::tools::{create_smeared_timestamp, get_abs_path}; -use crate::{chat, EventType}; /// The current API version. /// If `min_api` in manifest.toml is set to a larger value, From 9b9703a48e8e2d4a15a8e8fe32f5273e97f5ef66 Mon Sep 17 00:00:00 2001 From: link2xt Date: Thu, 27 Jul 2023 18:23:56 +0000 Subject: [PATCH 025/102] refactor: replace DcKey.load_self trait method with functions --- src/contact.rs | 4 +- src/context.rs | 4 +- src/e2ee.rs | 11 ++-- src/imex.rs | 6 +- src/key.rs | 126 ++++++++++++++++--------------------- src/mimeparser.rs | 4 +- src/securejoin.rs | 15 ++--- src/securejoin/bobstate.rs | 4 +- 8 files changed, 77 insertions(+), 97 deletions(-) diff --git a/src/contact.rs b/src/contact.rs index 9492ffd09..be3bbd105 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -25,7 +25,7 @@ use crate::config::Config; use crate::constants::{Blocked, Chattype, DC_GCL_ADD_SELF, DC_GCL_VERIFIED_ONLY}; use crate::context::Context; use crate::events::EventType; -use crate::key::{DcKey, SignedPublicKey}; +use crate::key::{load_self_public_key, DcKey}; use crate::login_param::LoginParam; use crate::message::MessageState; use crate::mimeparser::AvatarAction; @@ -1009,7 +1009,7 @@ impl Contact { let finger_prints = stock_str::finger_prints(context).await; ret += &format!("{stock_message}.\n{finger_prints}:"); - let fingerprint_self = SignedPublicKey::load_self(context) + let fingerprint_self = load_self_public_key(context) .await? .fingerprint() .to_string(); diff --git a/src/context.rs b/src/context.rs index 8209f445f..a6d649c76 100644 --- a/src/context.rs +++ b/src/context.rs @@ -19,7 +19,7 @@ use crate::constants::DC_VERSION_STR; use crate::contact::Contact; use crate::debug_logging::DebugLogging; use crate::events::{Event, EventEmitter, EventType, Events}; -use crate::key::{DcKey, SignedPublicKey}; +use crate::key::{load_self_public_key, DcKey as _}; use crate::login_param::LoginParam; use crate::message::{self, MessageState, MsgId}; use crate::quota::QuotaInfo; @@ -580,7 +580,7 @@ impl Context { .sql .count("SELECT COUNT(*) FROM acpeerstates;", ()) .await?; - let fingerprint_str = match SignedPublicKey::load_self(self).await { + let fingerprint_str = match load_self_public_key(self).await { Ok(key) => key.fingerprint().hex(), Err(err) => format!(""), }; diff --git a/src/e2ee.rs b/src/e2ee.rs index 2addaf56d..6a966b488 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -6,7 +6,7 @@ use num_traits::FromPrimitive; use crate::aheader::{Aheader, EncryptPreference}; use crate::config::Config; use crate::context::Context; -use crate::key::{DcKey, SignedPublicKey, SignedSecretKey}; +use crate::key::{load_self_public_key, load_self_secret_key, SignedPublicKey}; use crate::peerstate::{Peerstate, PeerstateVerifiedStatus}; use crate::pgp; @@ -23,7 +23,7 @@ impl EncryptHelper { EncryptPreference::from_i32(context.get_config_int(Config::E2eeEnabled).await?) .unwrap_or_default(); let addr = context.get_primary_self_addr().await?; - let public_key = SignedPublicKey::load_self(context).await?; + let public_key = load_self_public_key(context).await?; Ok(EncryptHelper { prefer_encrypt, @@ -115,7 +115,7 @@ impl EncryptHelper { keyring.push(key); } keyring.push(self.public_key.clone()); - let sign_key = SignedSecretKey::load_self(context).await?; + let sign_key = load_self_secret_key(context).await?; let raw_message = mail_to_encrypt.build().as_string().into_bytes(); @@ -131,7 +131,7 @@ impl EncryptHelper { context: &Context, mail: lettre_email::PartBuilder, ) -> Result<(lettre_email::MimeMessage, String)> { - let sign_key = SignedSecretKey::load_self(context).await?; + let sign_key = load_self_secret_key(context).await?; let mime_message = mail.build(); let signature = pgp::pk_calc_signature(mime_message.as_string().as_bytes(), &sign_key)?; Ok((mime_message, signature)) @@ -146,7 +146,7 @@ impl EncryptHelper { /// private key will be present. // TODO, remove this once deltachat::key::Key no longer exists. pub async fn ensure_secret_key_exists(context: &Context) -> Result<()> { - SignedPublicKey::load_self(context).await?; + load_self_public_key(context).await?; Ok(()) } @@ -154,6 +154,7 @@ pub async fn ensure_secret_key_exists(context: &Context) -> Result<()> { mod tests { use super::*; use crate::chat; + use crate::key::DcKey; use crate::message::{Message, Viewtype}; use crate::param::Param; use crate::test_utils::{bob_keypair, TestContext}; diff --git a/src/imex.rs b/src/imex.rs index f7f0dcfb1..94c9c97a5 100644 --- a/src/imex.rs +++ b/src/imex.rs @@ -19,7 +19,9 @@ use crate::contact::ContactId; use crate::context::Context; use crate::e2ee; use crate::events::EventType; -use crate::key::{self, DcKey, DcSecretKey, SignedPublicKey, SignedSecretKey}; +use crate::key::{ + self, load_self_secret_key, DcKey, DcSecretKey, SignedPublicKey, SignedSecretKey, +}; use crate::log::LogExt; use crate::message::{Message, MsgId, Viewtype}; use crate::mimeparser::SystemMessage; @@ -186,7 +188,7 @@ pub async fn render_setup_file(context: &Context, passphrase: &str) -> Result None, true => Some(("Autocrypt-Prefer-Encrypt", "mutual")), diff --git a/src/key.rs b/src/key.rs index 8f2be2d83..9e2076bc6 100644 --- a/src/key.rs +++ b/src/key.rs @@ -3,11 +3,9 @@ use std::collections::BTreeMap; use std::fmt; use std::io::Cursor; -use std::pin::Pin; use anyhow::{ensure, Context as _, Result}; use base64::Engine as _; -use futures::Future; use num_traits::FromPrimitive; use pgp::composed::Deserializable; pub use pgp::composed::{SignedPublicKey, SignedSecretKey}; @@ -49,11 +47,6 @@ pub trait DcKey: Serialize + Deserializable + KeyTrait + Clone { Self::from_armor_single(Cursor::new(bytes)).context("rPGP error") } - /// Load the users' default key from the database. - fn load_self<'a>( - context: &'a Context, - ) -> Pin> + 'a + Send>>; - /// Serialise the key as bytes. fn to_bytes(&self) -> Vec { // Not using Serialize::to_bytes() to make clear *why* it is @@ -84,38 +77,55 @@ pub trait DcKey: Serialize + Deserializable + KeyTrait + Clone { } } -impl DcKey for SignedPublicKey { - fn load_self<'a>( - context: &'a Context, - ) -> Pin> + 'a + Send>> { - Box::pin(async move { - let addr = context.get_primary_self_addr().await?; - match context - .sql - .query_row_optional( - r#" - SELECT public_key - FROM keypairs - WHERE addr=? - AND is_default=1; - "#, - (addr,), - |row| { - let bytes: Vec = row.get(0)?; - Ok(bytes) - }, - ) - .await? - { - Some(bytes) => Self::from_slice(&bytes), - None => { - let keypair = generate_keypair(context).await?; - Ok(keypair.public) - } - } - }) +pub(crate) async fn load_self_public_key(context: &Context) -> Result { + match context + .sql + .query_row_optional( + r#"SELECT public_key + FROM keypairs + WHERE addr=(SELECT value FROM config WHERE keyname="configured_addr") + AND is_default=1"#, + (), + |row| { + let bytes: Vec = row.get(0)?; + Ok(bytes) + }, + ) + .await? + { + Some(bytes) => SignedPublicKey::from_slice(&bytes), + None => { + let keypair = generate_keypair(context).await?; + Ok(keypair.public) + } } +} +pub(crate) async fn load_self_secret_key(context: &Context) -> Result { + match context + .sql + .query_row_optional( + r#"SELECT private_key + FROM keypairs + WHERE addr=(SELECT value FROM config WHERE keyname="configured_addr") + AND is_default=1"#, + (), + |row| { + let bytes: Vec = row.get(0)?; + Ok(bytes) + }, + ) + .await? + { + Some(bytes) => SignedSecretKey::from_slice(&bytes), + None => { + let keypair = generate_keypair(context).await?; + Ok(keypair.secret) + } + } +} + +impl DcKey for SignedPublicKey { fn to_asc(&self, header: Option<(&str, &str)>) -> String { // Not using .to_armored_string() to make clear *why* it is // safe to ignore this error. @@ -134,36 +144,6 @@ impl DcKey for SignedPublicKey { } impl DcKey for SignedSecretKey { - fn load_self<'a>( - context: &'a Context, - ) -> Pin> + 'a + Send>> { - Box::pin(async move { - match context - .sql - .query_row_optional( - r#" - SELECT private_key - FROM keypairs - WHERE addr=(SELECT value FROM config WHERE keyname="configured_addr") - AND is_default=1; - "#, - (), - |row| { - let bytes: Vec = row.get(0)?; - Ok(bytes) - }, - ) - .await? - { - Some(bytes) => Self::from_slice(&bytes), - None => { - let keypair = generate_keypair(context).await?; - Ok(keypair.secret) - } - } - }) - } - fn to_asc(&self, header: Option<(&str, &str)>) -> String { // Not using .to_armored_string() to make clear *why* it is // safe to do these unwraps. @@ -521,9 +501,9 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD async fn test_load_self_existing() { let alice = alice_keypair(); let t = TestContext::new_alice().await; - let pubkey = SignedPublicKey::load_self(&t).await.unwrap(); + let pubkey = load_self_public_key(&t).await.unwrap(); assert_eq!(alice.public, pubkey); - let seckey = SignedSecretKey::load_self(&t).await.unwrap(); + let seckey = load_self_secret_key(&t).await.unwrap(); assert_eq!(alice.secret, seckey); } @@ -533,7 +513,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD t.set_config(Config::ConfiguredAddr, Some("alice@example.org")) .await .unwrap(); - let key = SignedPublicKey::load_self(&t).await; + let key = load_self_public_key(&t).await; assert!(key.is_ok()); } @@ -543,7 +523,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD t.set_config(Config::ConfiguredAddr, Some("alice@example.org")) .await .unwrap(); - let key = SignedSecretKey::load_self(&t).await; + let key = load_self_secret_key(&t).await; assert!(key.is_ok()); } @@ -560,7 +540,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD thread::spawn(move || { tokio::runtime::Runtime::new() .unwrap() - .block_on(SignedPublicKey::load_self(&ctx)) + .block_on(load_self_public_key(&ctx)) }) }; let thr1 = { @@ -568,7 +548,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD thread::spawn(move || { tokio::runtime::Runtime::new() .unwrap() - .block_on(SignedPublicKey::load_self(&ctx)) + .block_on(load_self_public_key(&ctx)) }) }; let res0 = thr0.join().unwrap(); diff --git a/src/mimeparser.rs b/src/mimeparser.rs index bd0879398..50678419b 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -27,7 +27,7 @@ use crate::decrypt::{ use crate::dehtml::dehtml; use crate::events::EventType; use crate::headerdef::{HeaderDef, HeaderDefMap}; -use crate::key::{DcKey, Fingerprint, SignedPublicKey, SignedSecretKey}; +use crate::key::{load_self_secret_key, DcKey, Fingerprint, SignedPublicKey}; use crate::message::{self, set_msg_failed, update_msg_state, MessageState, MsgId, Viewtype}; use crate::param::{Param, Params}; use crate::peerstate::Peerstate; @@ -275,7 +275,7 @@ impl MimeMessage { headers.remove("chat-verified"); let from = from.context("No from in message")?; - let private_keyring = vec![SignedSecretKey::load_self(context) + let private_keyring = vec![load_self_secret_key(context) .await .context("Failed to get own key")?]; diff --git a/src/securejoin.rs b/src/securejoin.rs index ba4b9743c..1312dec66 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -14,7 +14,7 @@ use crate::context::Context; use crate::e2ee::ensure_secret_key_exists; use crate::events::EventType; use crate::headerdef::HeaderDef; -use crate::key::{DcKey, Fingerprint, SignedPublicKey}; +use crate::key::{load_self_public_key, DcKey, Fingerprint}; use crate::message::{Message, Viewtype}; use crate::mimeparser::{MimeMessage, SystemMessage}; use crate::param::Param; @@ -130,7 +130,7 @@ pub async fn get_securejoin_qr(context: &Context, group: Option) -> Resu } async fn get_self_fingerprint(context: &Context) -> Option { - match SignedPublicKey::load_self(context).await { + match load_self_public_key(context).await { Ok(key) => Some(key.fingerprint()), Err(_) => { warn!(context, "get_self_fingerprint(): failed to load key"); @@ -884,10 +884,7 @@ mod tests { "vc-request-with-auth" ); assert!(msg.get_header(HeaderDef::SecureJoinAuth).is_some()); - let bob_fp = SignedPublicKey::load_self(&bob.ctx) - .await - .unwrap() - .fingerprint(); + let bob_fp = load_self_public_key(&bob.ctx).await.unwrap().fingerprint(); assert_eq!( *msg.get_header(HeaderDef::SecureJoinFingerprint).unwrap(), bob_fp.hex() @@ -1029,7 +1026,7 @@ mod tests { let bob = tcm.bob().await; // Ensure Bob knows Alice_FP - let alice_pubkey = SignedPublicKey::load_self(&alice.ctx).await?; + let alice_pubkey = load_self_public_key(&alice.ctx).await?; let peerstate = Peerstate { addr: "alice@example.org".into(), last_seen: 10, @@ -1083,7 +1080,7 @@ mod tests { "vc-request-with-auth" ); assert!(msg.get_header(HeaderDef::SecureJoinAuth).is_some()); - let bob_fp = SignedPublicKey::load_self(&bob.ctx).await?.fingerprint(); + let bob_fp = load_self_public_key(&bob.ctx).await?.fingerprint(); assert_eq!( *msg.get_header(HeaderDef::SecureJoinFingerprint).unwrap(), bob_fp.hex() @@ -1254,7 +1251,7 @@ mod tests { "vg-request-with-auth" ); assert!(msg.get_header(HeaderDef::SecureJoinAuth).is_some()); - let bob_fp = SignedPublicKey::load_self(&bob.ctx).await?.fingerprint(); + let bob_fp = load_self_public_key(&bob.ctx).await?.fingerprint(); assert_eq!( *msg.get_header(HeaderDef::SecureJoinFingerprint).unwrap(), bob_fp.hex() diff --git a/src/securejoin/bobstate.rs b/src/securejoin/bobstate.rs index 2c48c54f2..b46b45bed 100644 --- a/src/securejoin/bobstate.rs +++ b/src/securejoin/bobstate.rs @@ -17,7 +17,7 @@ use crate::contact::{Contact, Origin}; use crate::context::Context; use crate::events::EventType; use crate::headerdef::HeaderDef; -use crate::key::{DcKey, SignedPublicKey}; +use crate::key::{load_self_public_key, DcKey}; use crate::message::{Message, Viewtype}; use crate::mimeparser::{MimeMessage, SystemMessage}; use crate::param::Param; @@ -448,7 +448,7 @@ async fn send_handshake_message( }; // Sends our own fingerprint in the Secure-Join-Fingerprint header. - let bob_fp = SignedPublicKey::load_self(context).await?.fingerprint(); + let bob_fp = load_self_public_key(context).await?.fingerprint(); msg.param.set(Param::Arg3, bob_fp.hex()); // Sends the grpid in the Secure-Join-Group header. From a02a593f470fc49acea54cdbc46554ecf2d39ed4 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 28 Jul 2023 23:14:59 +0200 Subject: [PATCH 026/102] fix example; this was changed some time ago, see https://docs.webxdc.org/spec.html#sendupdate --- deltachat-ffi/deltachat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 11fd5e369..38b4b97c4 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -1110,7 +1110,7 @@ dc_reactions_t* dc_get_msg_reactions (dc_context_t *context, int msg_id); * * In JS land, that would be mapped to something as: * ``` - * success = window.webxdc.sendUpdate('{"action":"move","src":"A3","dest":"B4"}', 'move A3 B4'); + * success = window.webxdc.sendUpdate('{payload: {"action":"move","src":"A3","dest":"B4"}}', 'move A3 B4'); * ``` * `context` and `msg_id` are not needed in JS as those are unique within a webxdc instance. * See dc_get_webxdc_status_updates() for the receiving counterpart. From 85739ba6ad7d3a3c9a39f991656b832d998cb56c Mon Sep 17 00:00:00 2001 From: link2xt Date: Fri, 28 Jul 2023 16:01:31 +0000 Subject: [PATCH 027/102] refactor: make last_added_location_id an Option --- src/chat.rs | 5 ++--- src/mimefactory.rs | 10 +++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/chat.rs b/src/chat.rs index 705f5dbfc..dc9896397 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -2389,14 +2389,13 @@ async fn create_send_msg_job(context: &Context, msg_id: MsgId) -> Result { in_reply_to: String, references: String, req_mdn: bool, - last_added_location_id: u32, + last_added_location_id: Option, /// If the created mime-structure contains sync-items, /// the IDs of these items are listed here. @@ -85,7 +85,7 @@ pub struct RenderedEmail { // pub envelope: Envelope, pub is_encrypted: bool, pub is_gossiped: bool, - pub last_added_location_id: u32, + pub last_added_location_id: Option, /// A comma-separated string of sync-IDs that are used by the rendered email /// and must be deleted once the message is actually queued for sending @@ -223,7 +223,7 @@ impl<'a> MimeFactory<'a> { in_reply_to, references, req_mdn, - last_added_location_id: 0, + last_added_location_id: None, sync_ids_to_delete: None, attach_selfavatar, }; @@ -264,7 +264,7 @@ impl<'a> MimeFactory<'a> { in_reply_to: String::default(), references: String::default(), req_mdn: false, - last_added_location_id: 0, + last_added_location_id: None, sync_ids_to_delete: None, attach_selfavatar: false, }; @@ -876,7 +876,7 @@ impl<'a> MimeFactory<'a> { .body(kml_content); if !self.msg.param.exists(Param::SetLatitude) { // otherwise, the independent location is already filed - self.last_added_location_id = last_added_location_id; + self.last_added_location_id = Some(last_added_location_id); } Ok(part) } From b784415c57af7d6d484e6369e3316c2110b31cb1 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 29 Jul 2023 18:05:05 +0000 Subject: [PATCH 028/102] refactor: move dc_preconfigure_keypair() implementation into `deltachat` crate This allows to hide `DcKey` trait from public API. --- deltachat-ffi/src/lib.rs | 25 ++++++++----------------- src/key.rs | 25 ++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index bee0167d8..58d238fd8 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -29,10 +29,9 @@ use deltachat::contact::{Contact, ContactId, Origin}; use deltachat::context::Context; use deltachat::ephemeral::Timer as EphemeralTimer; use deltachat::imex::BackupProvider; -use deltachat::key::DcKey; +use deltachat::key::preconfigure_keypair; use deltachat::message::MsgId; use deltachat::net::read_url_blob; -use deltachat::pgp::KeyPair; use deltachat::qr_code_generator::{generate_backup_qr, get_securejoin_qr_svg}; use deltachat::reaction::{get_msg_reactions, send_reaction, Reactions}; use deltachat::stock_str::StockMessage; @@ -796,21 +795,13 @@ pub unsafe extern "C" fn dc_preconfigure_keypair( return 0; } let ctx = &*context; - block_on(async move { - let addr = tools::EmailAddress::new(&to_string_lossy(addr))?; - let public = key::SignedPublicKey::from_asc(&to_string_lossy(public_data))?.0; - let secret = key::SignedSecretKey::from_asc(&to_string_lossy(secret_data))?.0; - let keypair = KeyPair { - addr, - public, - secret, - }; - key::store_self_keypair(ctx, &keypair, key::KeyPairUse::Default).await?; - Ok::<_, anyhow::Error>(1) - }) - .context("Failed to save keypair") - .log_err(ctx) - .unwrap_or(0) + let addr = to_string_lossy(addr); + let public_data = to_string_lossy(public_data); + let secret_data = to_string_lossy(secret_data); + block_on(preconfigure_keypair(ctx, &addr, &public_data, &secret_data)) + .context("Failed to save keypair") + .log_err(ctx) + .is_ok() as libc::c_int } #[no_mangle] diff --git a/src/key.rs b/src/key.rs index 9e2076bc6..75dc5342f 100644 --- a/src/key.rs +++ b/src/key.rs @@ -24,7 +24,7 @@ use crate::tools::{time, EmailAddress}; /// This trait is implemented for rPGP's [SignedPublicKey] and /// [SignedSecretKey] types and makes working with them a little /// easier in the deltachat world. -pub trait DcKey: Serialize + Deserializable + KeyTrait + Clone { +pub(crate) trait DcKey: Serialize + Deserializable + KeyTrait + Clone { /// Create a key from some bytes. fn from_slice(bytes: &[u8]) -> Result { Ok(::from_bytes(Cursor::new(bytes))?) @@ -307,6 +307,29 @@ pub async fn store_self_keypair( Ok(()) } +/// Saves a keypair as the default keys. +/// +/// This API is used for testing purposes +/// to avoid generating the key in tests. +/// Use import/export APIs instead. +pub async fn preconfigure_keypair( + context: &Context, + addr: &str, + public_data: &str, + secret_data: &str, +) -> Result<()> { + let addr = EmailAddress::new(addr)?; + let public = SignedPublicKey::from_asc(public_data)?.0; + let secret = SignedSecretKey::from_asc(secret_data)?.0; + let keypair = KeyPair { + addr, + public, + secret, + }; + store_self_keypair(context, &keypair, KeyPairUse::Default).await?; + Ok(()) +} + /// A key fingerprint #[derive(Clone, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] pub struct Fingerprint(Vec); From af013559de36dc892e0a8d96c392be2de646551a Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 29 Jul 2023 18:10:25 +0000 Subject: [PATCH 029/102] refactor: hide DcSecretKey trait from the API --- src/key.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/key.rs b/src/key.rs index 75dc5342f..01cd55d6d 100644 --- a/src/key.rs +++ b/src/key.rs @@ -164,7 +164,7 @@ impl DcKey for SignedSecretKey { /// Deltachat extension trait for secret keys. /// /// Provides some convenience wrappers only applicable to [SignedSecretKey]. -pub trait DcSecretKey { +pub(crate) trait DcSecretKey { /// Create a public key from a private one. fn split_public_key(&self) -> Result; } From 60bacbec4758324da0464bb8ca3efce2c0ccb65d Mon Sep 17 00:00:00 2001 From: Hocuri Date: Mon, 31 Jul 2023 18:59:45 +0200 Subject: [PATCH 030/102] feat: Don't show a contact as verified if their key changed since the verification (#4574) Don't show a contact as verified if their key changed in the meantime If a contact's key changed since the verification, then it's very unlikely that they still have the old, verified key. So, don't show them as verified anymore. This also means that you can't add a contact like this to a verified group, which is good. The documentation actually already described this (new) behavior: ```rust /// and if the key has not changed since this verification. ``` so, this adapts the code to the documentation. --- src/contact.rs | 3 +-- src/tests/verified_chats.rs | 13 ++++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/contact.rs b/src/contact.rs index be3bbd105..2998ae1ad 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -1211,7 +1211,6 @@ impl Contact { /// and if the key has not changed since this verification. /// /// The UI may draw a checkbox or something like that beside verified contacts. - /// pub async fn is_verified(&self, context: &Context) -> Result { // We're always sort of secured-verified as we could verify the key on this device any time with the key // on this device @@ -1220,7 +1219,7 @@ impl Contact { } if let Some(peerstate) = Peerstate::from_addr(context, &self.addr).await? { - if peerstate.verified_key.is_some() { + if peerstate.is_using_verified_key() { return Ok(VerifiedStatus::BidirectVerified); } } diff --git a/src/tests/verified_chats.rs b/src/tests/verified_chats.rs index e8a8f3e7f..131cf4b2a 100644 --- a/src/tests/verified_chats.rs +++ b/src/tests/verified_chats.rs @@ -627,7 +627,18 @@ async fn test_break_protection_then_verify_again() -> Result<()> { e2ee::ensure_secret_key_exists(&bob_new).await?; tcm.send_recv(&bob_new, &alice, "I have a new device").await; - assert_verified(&alice, &bob_new, ProtectionStatus::ProtectionBroken).await; + + let contact = alice.add_or_lookup_contact(&bob_new).await; + assert_eq!( + contact.is_verified(&alice).await.unwrap(), + // Bob sent a message with a new key, so he most likely doesn't have + // the old key anymore. This means that Alice's device should show + // him as unverified: + VerifiedStatus::Unverified + ); + let chat = alice.get_chat(&bob_new).await.unwrap(); + assert_eq!(chat.is_protected(), false); + assert_eq!(chat.is_protection_broken(), true); { let alice_bob_chat = alice.get_chat(&bob_new).await.unwrap(); From 8ed6d4d709583109755d37b7e53521b6f871b141 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sun, 23 Jul 2023 11:44:46 +0000 Subject: [PATCH 031/102] api!: make `MsgId.delete_from_db()` private Use `delete_msgs()` if you are using the Delta Chat core as a library and want to delete a message. --- src/ephemeral.rs | 8 ++++---- src/message.rs | 2 +- src/mimefactory.rs | 2 +- src/receive_imf.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ephemeral.rs b/src/ephemeral.rs index 54050a0e3..6d200b99b 100644 --- a/src/ephemeral.rs +++ b/src/ephemeral.rs @@ -986,7 +986,7 @@ mod tests { t.send_text(self_chat.id, "Saved message, which we delete manually") .await; let msg = t.get_last_msg_in(self_chat.id).await; - msg.id.delete_from_db(&t).await?; + msg.id.trash(&t).await?; check_msg_is_deleted(&t, &self_chat, msg.id).await; self_chat @@ -1003,7 +1003,7 @@ mod tests { .await .unwrap(); - // Set DeleteDeviceAfter to 1800s. Thend send a saved message which will + // Set DeleteDeviceAfter to 1800s. Then send a saved message which will // still be deleted after 3600s because DeleteDeviceAfter doesn't apply to saved messages. t.set_config(Config::DeleteDeviceAfter, Some("1800")) .await?; @@ -1261,8 +1261,8 @@ mod tests { ); let msg = alice.get_last_msg().await; - // Message is deleted from the database when its timer expires. - msg.id.delete_from_db(&alice).await?; + // Message is deleted when its timer expires. + msg.id.trash(&alice).await?; // Message with Message-ID , referencing and // , is received. The message is not in the diff --git a/src/message.rs b/src/message.rs index 6577f2a73..d72344465 100644 --- a/src/message.rs +++ b/src/message.rs @@ -113,7 +113,7 @@ WHERE id=?; } /// Deletes a message, corresponding MDNs and unsent SMTP messages from the database. - pub async fn delete_from_db(self, context: &Context) -> Result<()> { + pub(crate) async fn delete_from_db(self, context: &Context) -> Result<()> { // We don't use transactions yet, so remove MDNs first to make // sure they are not left while the message is deleted. context diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 931831ed8..47c06b326 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -1964,7 +1964,7 @@ mod tests { let incoming_msg = get_chat_msg(&t, new_msg.chat_id, 0, 2).await; if delete_original_msg { - incoming_msg.id.delete_from_db(&t).await.unwrap(); + incoming_msg.id.trash(&t).await.unwrap(); } if message_arrives_inbetween { diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 4222e69ab..994ba980b 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -1274,7 +1274,7 @@ RETURNING id if let Some(replace_msg_id) = replace_msg_id { // "Replace" placeholder with a message that has no parts. - replace_msg_id.delete_from_db(context).await?; + replace_msg_id.trash(context).await?; } chat_id.unarchive_if_not_muted(context, state).await?; From 8eee389c098d82098f04f3e1a6154126e15d4f0b Mon Sep 17 00:00:00 2001 From: link2xt Date: Sun, 23 Jul 2023 11:59:03 +0000 Subject: [PATCH 032/102] refactor: use SQL transaction in MsgId.delete_from_db() --- src/message.rs | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/message.rs b/src/message.rs index d72344465..594fab07e 100644 --- a/src/message.rs +++ b/src/message.rs @@ -114,23 +114,15 @@ WHERE id=?; /// Deletes a message, corresponding MDNs and unsent SMTP messages from the database. pub(crate) async fn delete_from_db(self, context: &Context) -> Result<()> { - // We don't use transactions yet, so remove MDNs first to make - // sure they are not left while the message is deleted. context .sql - .execute("DELETE FROM smtp WHERE msg_id=?", (self,)) - .await?; - context - .sql - .execute("DELETE FROM msgs_mdns WHERE msg_id=?;", (self,)) - .await?; - context - .sql - .execute("DELETE FROM msgs_status_updates WHERE msg_id=?;", (self,)) - .await?; - context - .sql - .execute("DELETE FROM msgs WHERE id=?;", (self,)) + .transaction(move |transaction| { + transaction.execute("DELETE FROM smtp WHERE msg_id=?", (self,))?; + transaction.execute("DELETE FROM msgs_mdns WHERE msg_id=?", (self,))?; + transaction.execute("DELETE FROM msgs_status_updates WHERE msg_id=?", (self,))?; + transaction.execute("DELETE FROM msgs WHERE id=?", (self,))?; + Ok(()) + }) .await?; Ok(()) } From c34edc582e83190db08bfd75ae9273a2a1c5c8d7 Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 31 Jul 2023 22:24:14 +0000 Subject: [PATCH 033/102] test: test that get_system_info() works over RPC backup import --- deltachat-rpc-client/tests/test_something.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deltachat-rpc-client/tests/test_something.py b/deltachat-rpc-client/tests/test_something.py index 6c2351ecf..9a498470a 100644 --- a/deltachat-rpc-client/tests/test_something.py +++ b/deltachat-rpc-client/tests/test_something.py @@ -355,3 +355,5 @@ async def test_import_export(acfactory, tmp_path) -> None: files = list(tmp_path.glob("*.tar")) alice2 = await acfactory.get_unconfigured_account() await alice2.import_backup(files[0]) + + assert await alice2.manager.get_system_info() From 13e766bc37936802d12a5b0c63eca8ca8a58990f Mon Sep 17 00:00:00 2001 From: link2xt Date: Tue, 1 Aug 2023 15:02:32 +0000 Subject: [PATCH 034/102] feat(deltachat-rpc-server): add --openrpc option --- Cargo.lock | 8 ++++---- deltachat-jsonrpc/Cargo.toml | 2 +- deltachat-jsonrpc/src/api/mod.rs | 6 +----- deltachat-rpc-client/tests/test_something.py | 10 ++++++++++ deltachat-rpc-server/Cargo.toml | 2 +- deltachat-rpc-server/README.md | 3 +++ deltachat-rpc-server/src/main.rs | 7 +++++++ 7 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3807895c0..8b881be77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5748,9 +5748,9 @@ dependencies = [ [[package]] name = "yerpc" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30fc983d32883ecb563227a2dcdcbe8567decd9c533b5ecca7e3099e2f7d4c96" +checksum = "75b5547af776328f66a5476ea3b7c0789e6fed164eb32d1a2122cfb39ffa505d" dependencies = [ "anyhow", "async-channel", @@ -5771,9 +5771,9 @@ dependencies = [ [[package]] name = "yerpc_derive" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d6b8ce490e8719fe84d7d80ad4d58572b2ea9d7a83d156f6afd6ab3ad5cfb94" +checksum = "f321bb5f728fb066af06c5a994e4375f1f8b054ee6d650766f0bd68dfa4faefe" dependencies = [ "convert_case 0.5.0", "darling 0.14.4", diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index 925086448..c17f3c4d4 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -22,7 +22,7 @@ log = "0.4" async-channel = { version = "1.8.0" } futures = { version = "0.3.28" } serde_json = "1.0.99" -yerpc = { version = "0.5.1", features = ["anyhow_expose", "openrpc"] } +yerpc = { version = "0.5.2", features = ["anyhow_expose", "openrpc"] } typescript-type-def = { version = "0.5.5", features = ["json_value"] } tokio = { version = "1.29.1" } sanitize-filename = "0.4" diff --git a/deltachat-jsonrpc/src/api/mod.rs b/deltachat-jsonrpc/src/api/mod.rs index d9b6db8aa..5768d6eb5 100644 --- a/deltachat-jsonrpc/src/api/mod.rs +++ b/deltachat-jsonrpc/src/api/mod.rs @@ -142,11 +142,7 @@ impl CommandApi { } } -#[rpc( - all_positional, - ts_outdir = "typescript/generated", - openrpc_outdir = "openrpc" -)] +#[rpc(all_positional, ts_outdir = "typescript/generated")] impl CommandApi { /// Test function. async fn sleep(&self, delay: f64) { diff --git a/deltachat-rpc-client/tests/test_something.py b/deltachat-rpc-client/tests/test_something.py index 9a498470a..77fdb0d3b 100644 --- a/deltachat-rpc-client/tests/test_something.py +++ b/deltachat-rpc-client/tests/test_something.py @@ -1,4 +1,6 @@ import asyncio +import json +import subprocess from unittest.mock import MagicMock import pytest @@ -357,3 +359,11 @@ async def test_import_export(acfactory, tmp_path) -> None: await alice2.import_backup(files[0]) assert await alice2.manager.get_system_info() + + +def test_openrpc_command_line() -> None: + """Test that "deltachat-rpc-server --openrpc" command returns an OpenRPC specification.""" + out = subprocess.run(["deltachat-rpc-server", "--openrpc"], capture_output=True).stdout + openrpc = json.loads(out) + assert "openrpc" in openrpc + assert "methods" in openrpc diff --git a/deltachat-rpc-server/Cargo.toml b/deltachat-rpc-server/Cargo.toml index 9560a0f22..03a480c5a 100644 --- a/deltachat-rpc-server/Cargo.toml +++ b/deltachat-rpc-server/Cargo.toml @@ -21,7 +21,7 @@ serde_json = "1.0.99" serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.29.1", features = ["io-std"] } tokio-util = "0.7.8" -yerpc = { version = "0.5.1", features = ["anyhow_expose"] } +yerpc = { version = "0.5.2", features = ["anyhow_expose", "openrpc"] } [features] default = ["vendored"] diff --git a/deltachat-rpc-server/README.md b/deltachat-rpc-server/README.md index 2027072a5..be8c0c562 100644 --- a/deltachat-rpc-server/README.md +++ b/deltachat-rpc-server/README.md @@ -32,3 +32,6 @@ languages other than Rust, for example: 1. Python: https://github.com/deltachat/deltachat-core-rust/tree/master/deltachat-rpc-client/ 2. Go: https://github.com/deltachat/deltachat-rpc-client-go/ + +Run `deltachat-rpc-server --version` to check the version of the server. +Run `deltachat-rpc-server --openrpc` to get [OpenRPC](https://open-rpc.org/) specification of the provided JSON-RPC API. diff --git a/deltachat-rpc-server/src/main.rs b/deltachat-rpc-server/src/main.rs index 1a3049f85..4be58760b 100644 --- a/deltachat-rpc-server/src/main.rs +++ b/deltachat-rpc-server/src/main.rs @@ -10,6 +10,7 @@ use deltachat::constants::DC_VERSION_STR; use deltachat_jsonrpc::api::{Accounts, CommandApi}; use futures_lite::stream::StreamExt; use tokio::io::{self, AsyncBufReadExt, BufReader}; +use yerpc::RpcServer as _; #[cfg(target_family = "unix")] use tokio::signal::unix as signal_unix; @@ -39,6 +40,12 @@ async fn main_impl() -> Result<()> { } eprintln!("{}", &*DC_VERSION_STR); return Ok(()); + } else if first_arg.to_str() == Some("--openrpc") { + if let Some(arg) = args.next() { + return Err(anyhow!("Unrecognized argument {:?}", arg)); + } + println!("{}", CommandApi::openrpc_specification()?); + return Ok(()); } else { return Err(anyhow!("Unrecognized option {:?}", first_arg)); } From d95843b0bfb9f0b15353c1d86c015aa3f920f352 Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 2 Aug 2023 03:23:19 +0000 Subject: [PATCH 035/102] chore(deps): update dependencies --- Cargo.lock | 150 +++++++++++++++++++++++++++-------------------------- deny.toml | 2 +- 2 files changed, 78 insertions(+), 74 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8b881be77..ff1e70736 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,17 +41,6 @@ dependencies = [ "cpufeatures", ] -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom 0.2.10", - "once_cell", - "version_check", -] - [[package]] name = "ahash" version = "0.8.3" @@ -169,7 +158,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.23", + "time 0.3.24", ] [[package]] @@ -287,7 +276,7 @@ checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -630,9 +619,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "51f1226cd9da55587234753d1245dd5b132343ea240f26b6a9003d68706141ba" +dependencies = [ + "libc", +] [[package]] name = "cfb-mode" @@ -1015,7 +1007,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -1249,7 +1241,7 @@ name = "deltachat_derive" version = "2.0.0" dependencies = [ "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -1319,6 +1311,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "deranged" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8810e7e2cf385b1e9b50d68264908ec367ba642c96d02edfe61c39e88e2a3c01" + [[package]] name = "derive_builder" version = "0.12.0" @@ -1449,7 +1447,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -1749,7 +1747,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -1773,9 +1771,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", @@ -2052,7 +2050,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -2188,9 +2186,6 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.6", -] [[package]] name = "hashbrown" @@ -2198,7 +2193,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" dependencies = [ - "ahash 0.8.3", + "ahash", "allocator-api2", ] @@ -2675,9 +2670,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "lock_api" @@ -2727,7 +2722,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] @@ -2738,9 +2733,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matchit" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" +checksum = "67827e6ea8ee8a7c4a72227ef4fc08957040acffdb5f122733b24fa12daff41b" [[package]] name = "md-5" @@ -2974,7 +2969,7 @@ checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -3088,7 +3083,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -3325,7 +3320,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -3438,9 +3433,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc55135a600d700580e406b4de0d59cb9ad25e344a3a091a97ded2622ec4ec6" +checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e" [[package]] name = "postcard" @@ -3776,7 +3771,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring", - "time 0.3.23", + "time 0.3.24", "yasna", ] @@ -3811,12 +3806,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ "aho-corasick", "memchr", + "regex-automata 0.3.4", "regex-syntax 0.7.4", ] @@ -3829,6 +3825,17 @@ dependencies = [ "regex-syntax 0.6.29", ] +[[package]] +name = "regex-automata" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.4", +] + [[package]] name = "regex-syntax" version = "0.6.29" @@ -4248,9 +4255,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.175" +version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d25439cd7397d044e2748a6fe2432b5e85db703d6d097bd014b3c0ad1ebff0b" +checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed" dependencies = [ "serde_derive", ] @@ -4275,13 +4282,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.175" +version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b23f7ade6f110613c0d63858ddb8b94c1041f550eab58a16b371bdf2c9c80ab4" +checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -4297,9 +4304,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa", "ryu", @@ -4433,9 +4440,9 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "slab" @@ -4594,7 +4601,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -4616,9 +4623,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.27" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ "proc-macro2", "quote", @@ -4748,7 +4755,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -4774,10 +4781,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" +checksum = "b79eabcd964882a646b3584543ccabeae7869e9ac32a46f6f22b7a5bd405308b" dependencies = [ + "deranged", "itoa", "serde", "time-core", @@ -4792,9 +4800,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" +checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" dependencies = [ "time-core", ] @@ -4862,7 +4870,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -5025,7 +5033,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -5206,13 +5214,9 @@ checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-linebreak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5faade31a542b8b35855fff6e8def199853b2da8da256da52f52f1316ee3137" -dependencies = [ - "hashbrown 0.12.3", - "regex", -] +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" @@ -5362,7 +5366,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", "wasm-bindgen-shared", ] @@ -5396,7 +5400,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5666,9 +5670,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.5.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" +checksum = "f46aab759304e4d7b2075a9aecba26228bb073ee8c50db796b2c72c676b5d807" dependencies = [ "memchr", ] @@ -5719,14 +5723,14 @@ dependencies = [ "oid-registry", "rusticata-macros", "thiserror", - "time 0.3.23", + "time 0.3.24", ] [[package]] name = "xattr" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea263437ca03c1522846a4ddafbca2542d0ad5ed9b784909d4b27b76f62bc34a" +checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" dependencies = [ "libc", ] @@ -5743,7 +5747,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ - "time 0.3.23", + "time 0.3.24", ] [[package]] @@ -5799,5 +5803,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.28", ] diff --git a/deny.toml b/deny.toml index 8f5b21649..e91ce49d3 100644 --- a/deny.toml +++ b/deny.toml @@ -10,7 +10,6 @@ ignore = [ # when upgrading. # Please keep this list alphabetically sorted. skip = [ - { name = "ahash", version = "0.7.6" }, { name = "base16ct", version = "0.1.1" }, { name = "base64", version = "<0.21" }, { name = "bitflags", version = "1.3.2" }, @@ -36,6 +35,7 @@ skip = [ { name = "rand_core", version = "<0.6" }, { name = "rand", version = "<0.8" }, { name = "redox_syscall", version = "0.2.16" }, + { name = "regex-automata", version = "0.1.10" }, { name = "regex-syntax", version = "0.6.29" }, { name = "sec1", version = "0.3.0" }, { name = "sha2", version = "<0.10" }, From 70000d9ebb981e686f5969a193285305040ce7b4 Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 2 Aug 2023 03:27:21 +0000 Subject: [PATCH 036/102] build: increase MSRV to 1.67.0 This is required by time v0.3.24 --- .github/workflows/ci.yml | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a61e289b..74bec1ea0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,9 +86,9 @@ jobs: - os: macos-latest rust: 1.71.0 - # Minimum Supported Rust Version = 1.66.0 + # Minimum Supported Rust Version = 1.67.0 - os: ubuntu-latest - rust: 1.66.0 + rust: 1.67.0 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 diff --git a/Cargo.toml b/Cargo.toml index 5625f62bb..21c535ad4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "deltachat" version = "1.118.0" edition = "2021" license = "MPL-2.0" -rust-version = "1.66" +rust-version = "1.67" [profile.dev] debug = 0 From e6cffd537ec9d13cd25006f614fe852f0786dad3 Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 31 Jul 2023 22:40:10 +0000 Subject: [PATCH 037/102] refactor: remove Chattype::Undefined --- src/chat.rs | 5 +---- src/chatlist.rs | 2 +- src/constants.rs | 7 ------- src/message.rs | 2 +- src/mimefactory.rs | 1 - src/mimeparser.rs | 2 +- src/summary.rs | 2 +- 7 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/chat.rs b/src/chat.rs index dc9896397..758092b98 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -357,7 +357,7 @@ impl ChatId { let chat = Chat::load_from_db(context, self).await?; match chat.typ { - Chattype::Undefined | Chattype::Broadcast => { + Chattype::Broadcast => { bail!("Can't block chat of type {:?}", chat.typ) } Chattype::Single => { @@ -398,7 +398,6 @@ impl ChatId { let chat = Chat::load_from_db(context, self).await?; match chat.typ { - Chattype::Undefined => bail!("Can't accept chat of undefined chattype"), Chattype::Single if chat.protected == ProtectionStatus::ProtectionBroken => { // The chat was in the 'Request' state because the protection was broken. // The user clicked 'Accept', so, now we want to set the status to Unprotected again: @@ -459,7 +458,6 @@ impl ChatId { } } Chattype::Mailinglist => bail!("Cannot protect mailing lists"), - Chattype::Undefined => bail!("Undefined group type"), }, ProtectionStatus::Unprotected | ProtectionStatus::ProtectionBroken => {} }; @@ -1286,7 +1284,6 @@ impl Chat { match self.typ { Chattype::Single | Chattype::Broadcast | Chattype::Mailinglist => Ok(true), Chattype::Group => is_contact_in_chat(context, self.id, ContactId::SELF).await, - Chattype::Undefined => Ok(false), } } diff --git a/src/chatlist.rs b/src/chatlist.rs index df8daac35..da817e05a 100644 --- a/src/chatlist.rs +++ b/src/chatlist.rs @@ -324,7 +324,7 @@ impl Chatlist { .context("loading contact failed")?; (Some(lastmsg), Some(lastcontact)) } - Chattype::Single | Chattype::Undefined => (Some(lastmsg), None), + Chattype::Single => (Some(lastmsg), None), } } } else { diff --git a/src/constants.rs b/src/constants.rs index c3eb33f1d..4adc2560e 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -118,7 +118,6 @@ pub const DC_CHAT_ID_LAST_SPECIAL: ChatId = ChatId::new(9); /// Chat type. #[derive( Debug, - Default, Display, Clone, Copy, @@ -134,10 +133,6 @@ pub const DC_CHAT_ID_LAST_SPECIAL: ChatId = ChatId::new(9); )] #[repr(u32)] pub enum Chattype { - /// Undefined chat type. - #[default] - Undefined = 0, - /// 1:1 chat. Single = 100, @@ -216,8 +211,6 @@ mod tests { #[test] fn test_chattype_values() { // values may be written to disk and must not change - assert_eq!(Chattype::Undefined, Chattype::default()); - assert_eq!(Chattype::Undefined, Chattype::from_i32(0).unwrap()); assert_eq!(Chattype::Single, Chattype::from_i32(100).unwrap()); assert_eq!(Chattype::Group, Chattype::from_i32(120).unwrap()); assert_eq!(Chattype::Mailinglist, Chattype::from_i32(140).unwrap()); diff --git a/src/message.rs b/src/message.rs index 594fab07e..d79208a8e 100644 --- a/src/message.rs +++ b/src/message.rs @@ -755,7 +755,7 @@ impl Message { Chattype::Group | Chattype::Broadcast | Chattype::Mailinglist => { Some(Contact::get_by_id(context, self.from_id).await?) } - Chattype::Single | Chattype::Undefined => None, + Chattype::Single => None, } } else { None diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 47c06b326..47e8a0801 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -897,7 +897,6 @@ impl<'a> MimeFactory<'a> { let mut meta_part = None; let send_verified_headers = match chat.typ { - Chattype::Undefined => bail!("Undefined chat type"), // In single chats, the protection status isn't necessarily the same for both sides, // so we don't send the Chat-Verified header: Chattype::Single => false, diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 04dfd0821..c0583ff4c 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -2182,7 +2182,7 @@ async fn ndn_maybe_add_info_msg( // If we get an NDN for the mailing list, just issue a warning. warn!(context, "ignoring NDN for mailing list."); } - Chattype::Single | Chattype::Undefined => {} + Chattype::Single => {} } Ok(()) } diff --git a/src/summary.rs b/src/summary.rs index 731f4edf0..dfeab5f59 100644 --- a/src/summary.rs +++ b/src/summary.rs @@ -82,7 +82,7 @@ impl Summary { .map(SummaryPrefix::Username) } } - Chattype::Single | Chattype::Undefined => None, + Chattype::Single => None, } }; From 3111bcde5ed064d2f2187eca3b6ac1a3f42526fd Mon Sep 17 00:00:00 2001 From: link2xt Date: Thu, 3 Aug 2023 15:58:40 +0000 Subject: [PATCH 038/102] refactor: flatten imports in deltachat-jsonrpc --- deltachat-jsonrpc/src/api/mod.rs | 46 ++++++++++++++++---------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/deltachat-jsonrpc/src/api/mod.rs b/deltachat-jsonrpc/src/api/mod.rs index 5768d6eb5..19dfbe03a 100644 --- a/deltachat-jsonrpc/src/api/mod.rs +++ b/deltachat-jsonrpc/src/api/mod.rs @@ -4,30 +4,30 @@ use std::{collections::HashMap, str::FromStr}; use anyhow::{anyhow, bail, ensure, Context, Result}; pub use deltachat::accounts::Accounts; -use deltachat::message::get_msg_read_receipts; -use deltachat::qr::Qr; -use deltachat::{ - chat::{ - self, add_contact_to_chat, forward_msgs, get_chat_media, get_chat_msgs, get_chat_msgs_ex, - marknoticed_chat, remove_contact_from_chat, Chat, ChatId, ChatItem, MessageListOptions, - ProtectionStatus, - }, - chatlist::Chatlist, - config::Config, - constants::DC_MSG_ID_DAYMARKER, - contact::{may_be_valid_addr, Contact, ContactId, Origin}, - context::get_info, - ephemeral::Timer, - imex, location, - message::{self, delete_msgs, markseen_msgs, Message, MessageState, MsgId, Viewtype}, - provider::get_provider_info, - qr, - qr_code_generator::{generate_backup_qr, get_securejoin_qr_svg}, - reaction::{get_msg_reactions, send_reaction}, - securejoin, - stock_str::StockMessage, - webxdc::StatusUpdateSerial, +use deltachat::chat::{ + self, add_contact_to_chat, forward_msgs, get_chat_media, get_chat_msgs, get_chat_msgs_ex, + marknoticed_chat, remove_contact_from_chat, Chat, ChatId, ChatItem, MessageListOptions, + ProtectionStatus, }; +use deltachat::chatlist::Chatlist; +use deltachat::config::Config; +use deltachat::constants::DC_MSG_ID_DAYMARKER; +use deltachat::contact::{may_be_valid_addr, Contact, ContactId, Origin}; +use deltachat::context::get_info; +use deltachat::ephemeral::Timer; +use deltachat::imex; +use deltachat::location; +use deltachat::message::get_msg_read_receipts; +use deltachat::message::{ + self, delete_msgs, markseen_msgs, Message, MessageState, MsgId, Viewtype, +}; +use deltachat::provider::get_provider_info; +use deltachat::qr::{self, Qr}; +use deltachat::qr_code_generator::{generate_backup_qr, get_securejoin_qr_svg}; +use deltachat::reaction::{get_msg_reactions, send_reaction}; +use deltachat::securejoin; +use deltachat::stock_str::StockMessage; +use deltachat::webxdc::StatusUpdateSerial; use sanitize_filename::is_sanitized; use tokio::fs; use tokio::sync::{watch, Mutex, RwLock}; From aecbebd5668ebfde5c3180a5b76084114c25a71e Mon Sep 17 00:00:00 2001 From: link2xt Date: Thu, 3 Aug 2023 15:59:47 +0000 Subject: [PATCH 039/102] docs: improve JSON-RPC API documentation --- deltachat-jsonrpc/src/api/mod.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/deltachat-jsonrpc/src/api/mod.rs b/deltachat-jsonrpc/src/api/mod.rs index 19dfbe03a..02027af0b 100644 --- a/deltachat-jsonrpc/src/api/mod.rs +++ b/deltachat-jsonrpc/src/api/mod.rs @@ -153,12 +153,12 @@ impl CommandApi { // Misc top level functions // --------------------------------------------- - /// Check if an email address is valid. + /// Checks if an email address is valid. async fn check_email_validity(&self, email: String) -> bool { may_be_valid_addr(&email) } - /// Get general system info. + /// Returns general system info. async fn get_system_info(&self) -> BTreeMap<&'static str, String> { get_info() } @@ -219,11 +219,13 @@ impl CommandApi { Ok(accounts) } + /// Starts background tasks for all accounts. async fn start_io_for_all_accounts(&self) -> Result<()> { self.accounts.read().await.start_io().await; Ok(()) } + /// Stops background tasks for all accounts. async fn stop_io_for_all_accounts(&self) -> Result<()> { self.accounts.read().await.stop_io().await; Ok(()) @@ -233,14 +235,16 @@ impl CommandApi { // Methods that work on individual accounts // --------------------------------------------- - async fn start_io(&self, id: u32) -> Result<()> { - let ctx = self.get_context(id).await?; + /// Starts background tasks for a single account. + async fn start_io(&self, account_id: u32) -> Result<()> { + let ctx = self.get_context(account_id).await?; ctx.start_io().await; Ok(()) } - async fn stop_io(&self, id: u32) -> Result<()> { - let ctx = self.get_context(id).await?; + /// Stops background tasks for a single account. + async fn stop_io(&self, account_id: u32) -> Result<()> { + let ctx = self.get_context(account_id).await?; ctx.stop_io().await; Ok(()) } @@ -307,11 +311,13 @@ impl CommandApi { ctx.get_info().await } + /// Sets the given configuration key. async fn set_config(&self, account_id: u32, key: String, value: Option) -> Result<()> { let ctx = self.get_context(account_id).await?; set_config(&ctx, &key, value.as_deref()).await } + /// Updates a batch of configuration values. async fn batch_set_config( &self, account_id: u32, @@ -343,6 +349,7 @@ impl CommandApi { Ok(qr_object) } + /// Returns configuration value for the given key. async fn get_config(&self, account_id: u32, key: String) -> Result> { let ctx = self.get_context(account_id).await?; get_config(&ctx, &key).await @@ -1863,7 +1870,7 @@ impl CommandApi { .context("path conversion to string failed") } - /// save a sticker to a collection/folder in the account's sticker folder + /// Saves a sticker to a collection/folder in the account's sticker folder. async fn misc_save_sticker( &self, account_id: u32, From e12044e6af0b0f8285b0b1f7bc51c102072d0404 Mon Sep 17 00:00:00 2001 From: link2xt Date: Thu, 3 Aug 2023 19:37:26 +0000 Subject: [PATCH 040/102] api!(deltachat-jsonrpc): use `kind` as a tag for all union types --- deltachat-jsonrpc/src/api/types/account.rs | 2 +- deltachat-jsonrpc/src/api/types/chat.rs | 9 +++++---- deltachat-jsonrpc/src/api/types/chat_list.rs | 2 +- deltachat-jsonrpc/src/api/types/events.rs | 2 +- deltachat-jsonrpc/src/api/types/message.rs | 2 +- deltachat-jsonrpc/src/api/types/qr.rs | 2 +- deltachat-jsonrpc/typescript/example/example.ts | 11 +++++------ deltachat-jsonrpc/typescript/src/client.ts | 16 ++++++++-------- deltachat-jsonrpc/typescript/test/online.ts | 8 ++++---- .../examples/echobot_advanced.py | 4 ++-- .../src/deltachat_rpc_client/chat.py | 6 +++--- .../src/deltachat_rpc_client/client.py | 4 ++-- .../src/deltachat_rpc_client/events.py | 2 +- .../src/deltachat_rpc_client/pytestplugin.py | 4 ++-- deltachat-rpc-client/tests/test_something.py | 10 +++++----- deltachat-rpc-client/tests/test_webxdc.py | 2 +- 16 files changed, 43 insertions(+), 43 deletions(-) diff --git a/deltachat-jsonrpc/src/api/types/account.rs b/deltachat-jsonrpc/src/api/types/account.rs index d27a53723..b2909109d 100644 --- a/deltachat-jsonrpc/src/api/types/account.rs +++ b/deltachat-jsonrpc/src/api/types/account.rs @@ -7,7 +7,7 @@ use typescript_type_def::TypeDef; use super::color_int_to_hex_string; #[derive(Serialize, TypeDef, schemars::JsonSchema)] -#[serde(tag = "type")] +#[serde(tag = "kind")] pub enum Account { #[serde(rename_all = "camelCase")] Configured { diff --git a/deltachat-jsonrpc/src/api/types/chat.rs b/deltachat-jsonrpc/src/api/types/chat.rs index c8d7d867f..e2146c8c1 100644 --- a/deltachat-jsonrpc/src/api/types/chat.rs +++ b/deltachat-jsonrpc/src/api/types/chat.rs @@ -167,10 +167,11 @@ impl BasicChat { } #[derive(Clone, Serialize, Deserialize, TypeDef, schemars::JsonSchema)] +#[serde(tag = "kind")] pub enum MuteDuration { NotMuted, Forever, - Until(i64), + Until { duration: i64 }, } impl MuteDuration { @@ -178,13 +179,13 @@ impl MuteDuration { match self { MuteDuration::NotMuted => Ok(chat::MuteDuration::NotMuted), MuteDuration::Forever => Ok(chat::MuteDuration::Forever), - MuteDuration::Until(n) => { - if n <= 0 { + MuteDuration::Until { duration } => { + if duration <= 0 { bail!("failed to read mute duration") } Ok(SystemTime::now() - .checked_add(Duration::from_secs(n as u64)) + .checked_add(Duration::from_secs(duration as u64)) .map_or(chat::MuteDuration::Forever, chat::MuteDuration::Until)) } } diff --git a/deltachat-jsonrpc/src/api/types/chat_list.rs b/deltachat-jsonrpc/src/api/types/chat_list.rs index 2c15165d9..510c20e20 100644 --- a/deltachat-jsonrpc/src/api/types/chat_list.rs +++ b/deltachat-jsonrpc/src/api/types/chat_list.rs @@ -18,7 +18,7 @@ use super::message::MessageViewtype; pub struct ChatListEntry(pub u32, pub u32); #[derive(Serialize, TypeDef, schemars::JsonSchema)] -#[serde(tag = "type")] +#[serde(tag = "kind")] pub enum ChatListItemFetchResult { #[serde(rename_all = "camelCase")] ChatListItem { diff --git a/deltachat-jsonrpc/src/api/types/events.rs b/deltachat-jsonrpc/src/api/types/events.rs index 0cfb02a84..dd03358bc 100644 --- a/deltachat-jsonrpc/src/api/types/events.rs +++ b/deltachat-jsonrpc/src/api/types/events.rs @@ -22,7 +22,7 @@ impl From for Event { } #[derive(Serialize, TypeDef, schemars::JsonSchema)] -#[serde(tag = "type")] +#[serde(tag = "kind")] pub enum EventType { /// The library-user may write an informational string to the log. /// diff --git a/deltachat-jsonrpc/src/api/types/message.rs b/deltachat-jsonrpc/src/api/types/message.rs index 9e50d90eb..2d4acec7e 100644 --- a/deltachat-jsonrpc/src/api/types/message.rs +++ b/deltachat-jsonrpc/src/api/types/message.rs @@ -19,7 +19,7 @@ use super::reactions::JSONRPCReactions; use super::webxdc::WebxdcMessageInfo; #[derive(Serialize, TypeDef, schemars::JsonSchema)] -#[serde(rename_all = "camelCase", tag = "variant")] +#[serde(rename_all = "camelCase", tag = "kind")] pub enum MessageLoadResult { Message(MessageObject), LoadingError { error: String }, diff --git a/deltachat-jsonrpc/src/api/types/qr.rs b/deltachat-jsonrpc/src/api/types/qr.rs index d53ebeab5..0f6d79c8c 100644 --- a/deltachat-jsonrpc/src/api/types/qr.rs +++ b/deltachat-jsonrpc/src/api/types/qr.rs @@ -4,7 +4,7 @@ use typescript_type_def::TypeDef; #[derive(Serialize, TypeDef, schemars::JsonSchema)] #[serde(rename = "Qr", rename_all = "camelCase")] -#[serde(tag = "type")] +#[serde(tag = "kind")] pub enum QrObject { AskVerifyContact { contact_id: u32, diff --git a/deltachat-jsonrpc/typescript/example/example.ts b/deltachat-jsonrpc/typescript/example/example.ts index d7b038e0c..e45bc18cc 100644 --- a/deltachat-jsonrpc/typescript/example/example.ts +++ b/deltachat-jsonrpc/typescript/example/example.ts @@ -35,7 +35,7 @@ async function run() { const accounts = await client.rpc.getAllAccounts(); console.log("accounts loaded", accounts); for (const account of accounts) { - if (account.type === "Configured") { + if (account.kind === "Configured") { write( $head, ` @@ -57,7 +57,7 @@ async function run() { clear($main); const selectedAccount = SELECTED_ACCOUNT; const info = await client.rpc.getAccountInfo(selectedAccount); - if (info.type !== "Configured") { + if (info.kind !== "Configured") { return write($main, "Account is not configured"); } write($main, `

${info.addr!}

`); @@ -81,8 +81,7 @@ async function run() { messageIds ); for (const [_messageId, message] of Object.entries(messages)) { - if (message.variant === "message") - write($main, `

${message.text}

`); + if (message.kind === "message") write($main, `

${message.text}

`); else write($main, `

loading error: ${message.error}

`); } } @@ -93,9 +92,9 @@ async function run() { $side, `

- [${event.type} on account ${accountId}]
+ [${event.kind} on account ${accountId}]
f1: ${JSON.stringify( - Object.assign({}, event, { type: undefined }) + Object.assign({}, event, { kind: undefined }) )}

` ); diff --git a/deltachat-jsonrpc/typescript/src/client.ts b/deltachat-jsonrpc/typescript/src/client.ts index 1a51b5e04..83cc2f7e7 100644 --- a/deltachat-jsonrpc/typescript/src/client.ts +++ b/deltachat-jsonrpc/typescript/src/client.ts @@ -6,22 +6,22 @@ import { WebsocketTransport, BaseTransport, Request } from "yerpc"; import { TinyEmitter } from "@deltachat/tiny-emitter"; type Events = { ALL: (accountId: number, event: EventType) => void } & { - [Property in EventType["type"]]: ( + [Property in EventType["kind"]]: ( accountId: number, - event: Extract + event: Extract ) => void; }; type ContextEvents = { ALL: (event: EventType) => void } & { - [Property in EventType["type"]]: ( - event: Extract + [Property in EventType["kind"]]: ( + event: Extract ) => void; }; export type DcEvent = EventType; -export type DcEventType = Extract< +export type DcEventType = Extract< EventType, - { type: T } + { kind: T } >; export class BaseDeltaChat< @@ -46,12 +46,12 @@ export class BaseDeltaChat< while (true) { const event = await this.rpc.getNextEvent(); //@ts-ignore - this.emit(event.event.type, event.contextId, event.event); + this.emit(event.event.kind, event.contextId, event.event); this.emit("ALL", event.contextId, event.event); if (this.contextEmitters[event.contextId]) { this.contextEmitters[event.contextId].emit( - event.event.type, + event.event.kind, //@ts-ignore event.event as any ); diff --git a/deltachat-jsonrpc/typescript/test/online.ts b/deltachat-jsonrpc/typescript/test/online.ts index 3ab6cb820..889b1e22e 100644 --- a/deltachat-jsonrpc/typescript/test/online.ts +++ b/deltachat-jsonrpc/typescript/test/online.ts @@ -29,8 +29,8 @@ describe("online tests", function () { serverHandle = await startServer(); dc = new DeltaChat(serverHandle.stdin, serverHandle.stdout, true); - dc.on("ALL", (contextId, { type }) => { - if (type !== "Info") console.log(contextId, type); + dc.on("ALL", (contextId, { kind }) => { + if (kind !== "Info") console.log(contextId, kind); }); account1 = await createTempUser(process.env.DCC_NEW_TMP_EMAIL); @@ -177,12 +177,12 @@ describe("online tests", function () { }); }); -async function waitForEvent( +async function waitForEvent( dc: DeltaChat, eventType: T, accountId: number, timeout: number = EVENT_TIMEOUT -): Promise> { +): Promise> { return new Promise((resolve, reject) => { const rejectTimeout = setTimeout( () => reject(new Error("Timeout reached before event came in")), diff --git a/deltachat-rpc-client/examples/echobot_advanced.py b/deltachat-rpc-client/examples/echobot_advanced.py index 3030941c8..4fcbc52f2 100644 --- a/deltachat-rpc-client/examples/echobot_advanced.py +++ b/deltachat-rpc-client/examples/echobot_advanced.py @@ -14,9 +14,9 @@ hooks = events.HookCollection() @hooks.on(events.RawEvent) async def log_event(event): - if event.type == EventType.INFO: + if event.kind == EventType.INFO: logging.info(event.msg) - elif event.type == EventType.WARNING: + elif event.kind == EventType.WARNING: logging.warning(event.msg) diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/chat.py b/deltachat-rpc-client/src/deltachat_rpc_client/chat.py index a9cfad8ab..5eb116118 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/chat.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/chat.py @@ -54,14 +54,14 @@ class Chat: """ if duration is not None: assert duration > 0, "Invalid duration" - dur: Union[str, dict] = {"Until": duration} + dur: dict = {"kind": "Until", "duration": duration} else: - dur = "Forever" + dur = {"kind": "Forever"} await self._rpc.set_chat_mute_duration(self.account.id, self.id, dur) async def unmute(self) -> None: """Unmute this chat.""" - await self._rpc.set_chat_mute_duration(self.account.id, self.id, "NotMuted") + await self._rpc.set_chat_mute_duration(self.account.id, self.id, {"kind": "NotMuted"}) async def pin(self) -> None: """Pin this chat.""" diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/client.py b/deltachat-rpc-client/src/deltachat_rpc_client/client.py index 5205a1ed9..c270fb0f7 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/client.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/client.py @@ -106,10 +106,10 @@ class Client: await self._process_messages() # Process old messages. while True: event = await self.account.wait_for_event() - event["type"] = EventType(event.type) + event["kind"] = EventType(event.kind) event["account"] = self.account await self._on_event(event) - if event.type == EventType.INCOMING_MSG: + if event.kind == EventType.INCOMING_MSG: await self._process_messages() stop = func(event) diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/events.py b/deltachat-rpc-client/src/deltachat_rpc_client/events.py index 4896527b9..2c1f71369 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/events.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/events.py @@ -83,7 +83,7 @@ class RawEvent(EventFilter): return False async def filter(self, event: "AttrDict") -> bool: - if self.types and event.type not in self.types: + if self.types and event.kind not in self.types: return False return await self._call_func(event) diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/pytestplugin.py b/deltachat-rpc-client/src/deltachat_rpc_client/pytestplugin.py index 9b207ecfa..8087327a6 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/pytestplugin.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/pytestplugin.py @@ -57,7 +57,7 @@ class ACFactory: while True: event = await account.wait_for_event() print(event) - if event.type == EventType.IMAP_INBOX_IDLE: + if event.kind == EventType.IMAP_INBOX_IDLE: break return account @@ -98,7 +98,7 @@ class ACFactory: group=group, ) - return await to_client.run_until(lambda e: e.type == EventType.INCOMING_MSG) + return await to_client.run_until(lambda e: e.kind == EventType.INCOMING_MSG) @pytest_asyncio.fixture diff --git a/deltachat-rpc-client/tests/test_something.py b/deltachat-rpc-client/tests/test_something.py index 77fdb0d3b..b28d2822e 100644 --- a/deltachat-rpc-client/tests/test_something.py +++ b/deltachat-rpc-client/tests/test_something.py @@ -45,7 +45,7 @@ async def test_acfactory(acfactory) -> None: account = await acfactory.new_configured_account() while True: event = await account.wait_for_event() - if event.type == EventType.CONFIGURE_PROGRESS: + if event.kind == EventType.CONFIGURE_PROGRESS: assert event.progress != 0 # Progress 0 indicates error. if event.progress == 1000: # Success break @@ -76,7 +76,7 @@ async def test_account(acfactory) -> None: while True: event = await bob.wait_for_event() - if event.type == EventType.INCOMING_MSG: + if event.kind == EventType.INCOMING_MSG: chat_id = event.chat_id msg_id = event.msg_id break @@ -146,7 +146,7 @@ async def test_chat(acfactory) -> None: while True: event = await bob.wait_for_event() - if event.type == EventType.INCOMING_MSG: + if event.kind == EventType.INCOMING_MSG: chat_id = event.chat_id msg_id = event.msg_id break @@ -232,7 +232,7 @@ async def test_message(acfactory) -> None: while True: event = await bob.wait_for_event() - if event.type == EventType.INCOMING_MSG: + if event.kind == EventType.INCOMING_MSG: chat_id = event.chat_id msg_id = event.msg_id break @@ -272,7 +272,7 @@ async def test_is_bot(acfactory) -> None: while True: event = await bob.wait_for_event() - if event.type == EventType.INCOMING_MSG: + if event.kind == EventType.INCOMING_MSG: msg_id = event.msg_id message = bob.get_message_by_id(msg_id) snapshot = await message.get_snapshot() diff --git a/deltachat-rpc-client/tests/test_webxdc.py b/deltachat-rpc-client/tests/test_webxdc.py index 8a0584d03..4111ca39e 100644 --- a/deltachat-rpc-client/tests/test_webxdc.py +++ b/deltachat-rpc-client/tests/test_webxdc.py @@ -13,7 +13,7 @@ async def test_webxdc(acfactory) -> None: while True: event = await bob.wait_for_event() - if event.type == EventType.INCOMING_MSG: + if event.kind == EventType.INCOMING_MSG: bob_chat_alice = bob.get_chat_by_id(event.chat_id) message = bob.get_message_by_id(event.msg_id) break From 3ab181fdf87de5fb7c723fb246538211e8e0d53e Mon Sep 17 00:00:00 2001 From: link2xt Date: Fri, 4 Aug 2023 20:08:20 +0000 Subject: [PATCH 041/102] build: update to Zig 0.11.0 --- scripts/zig-musl-check.sh | 2 +- scripts/zig-rpc-server.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/zig-musl-check.sh b/scripts/zig-musl-check.sh index 19d30d2cf..c164034b0 100755 --- a/scripts/zig-musl-check.sh +++ b/scripts/zig-musl-check.sh @@ -11,7 +11,7 @@ unset RUSTFLAGS # Pin Rust version to avoid uncontrolled changes in the compiler and linker flags. export RUSTUP_TOOLCHAIN=1.71.0 -ZIG_VERSION=0.11.0-dev.2213+515e1c93e +ZIG_VERSION=0.11.0 # Download Zig rm -fr "$ZIG_VERSION" "zig-linux-x86_64-$ZIG_VERSION.tar.xz" diff --git a/scripts/zig-rpc-server.sh b/scripts/zig-rpc-server.sh index 29e16121c..165169237 100755 --- a/scripts/zig-rpc-server.sh +++ b/scripts/zig-rpc-server.sh @@ -10,7 +10,7 @@ unset RUSTFLAGS # Pin Rust version to avoid uncontrolled changes in the compiler and linker flags. export RUSTUP_TOOLCHAIN=1.71.0 -ZIG_VERSION=0.11.0-dev.2213+515e1c93e +ZIG_VERSION=0.11.0 # Download Zig rm -fr "$ZIG_VERSION" "zig-linux-x86_64-$ZIG_VERSION.tar.xz" From 885f26ea8c793813b061e81cddda0df93bdd3ca6 Mon Sep 17 00:00:00 2001 From: Hocuri Date: Tue, 8 Aug 2023 11:34:52 +0200 Subject: [PATCH 042/102] test: Directly unwrap in TestContext::get_chat() (#4614) Directly unwrap in TestContext::get_chat() Turns out that all usages of get_chat() directly unwrapped, because in a test it doesn't make sense to handle the error of there being no chat. --- src/receive_imf/tests.rs | 2 +- src/securejoin.rs | 10 ++-------- src/test_utils.rs | 18 ++++++++++-------- src/tests/verified_chats.rs | 16 ++++++++-------- 4 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/receive_imf/tests.rs b/src/receive_imf/tests.rs index 5036b1a24..041ed20a0 100644 --- a/src/receive_imf/tests.rs +++ b/src/receive_imf/tests.rs @@ -2941,7 +2941,7 @@ async fn test_outgoing_private_reply_multidevice() -> Result<()> { let received = alice2.get_last_msg().await; // That's a regression test for https://github.com/deltachat/deltachat-core-rust/issues/2949: - assert_eq!(received.chat_id, alice2.get_chat(&bob).await.unwrap().id); + assert_eq!(received.chat_id, alice2.get_chat(&bob).await.id); let alice2_bob_contact = alice2.add_or_lookup_contact(&bob).await; assert_eq!(received.from_id, ContactId::SELF); diff --git a/src/securejoin.rs b/src/securejoin.rs index 1312dec66..34de7b658 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -1287,10 +1287,7 @@ mod tests { // Now Alice's chat with Bob should still be hidden, the verified message should // appear in the group chat. - let chat = alice - .get_chat(&bob) - .await - .expect("Alice has no 1:1 chat with bob"); + let chat = alice.get_chat(&bob).await; assert_eq!( chat.blocked, Blocked::Yes, @@ -1325,10 +1322,7 @@ mod tests { contact_alice.is_verified(&bob.ctx).await?, VerifiedStatus::BidirectVerified ); - let chat = bob - .get_chat(&alice) - .await - .expect("Bob has no 1:1 chat with Alice"); + let chat = bob.get_chat(&alice).await; assert_eq!( chat.blocked, Blocked::Yes, diff --git a/src/test_utils.rs b/src/test_utils.rs index 68bab184d..3b31a0ce6 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -587,19 +587,21 @@ impl TestContext { Contact::get_by_id(&self.ctx, contact_id).await.unwrap() } - /// Returns 1:1 [`Chat`] with another account, if it exists. + /// Returns 1:1 [`Chat`] with another account. Panics if it doesn't exist. /// /// This first creates a contact using the configured details on the other account, then - /// creates a 1:1 chat with this contact. - pub async fn get_chat(&self, other: &TestContext) -> Option { + /// gets the 1:1 chat with this contact. + pub async fn get_chat(&self, other: &TestContext) -> Chat { let contact = self.add_or_lookup_contact(other).await; - match ChatId::lookup_by_contact(&self.ctx, contact.id) + let chat_id = ChatId::lookup_by_contact(&self.ctx, contact.id) .await .unwrap() - { - Some(id) => Some(Chat::load_from_db(&self.ctx, id).await.unwrap()), - None => None, - } + .expect( + "There is no chat with this contact. \ + Hint: Use create_chat() instead of get_chat() if this is expected.", + ); + + Chat::load_from_db(&self.ctx, chat_id).await.unwrap() } /// Creates or returns an existing 1:1 [`Chat`] with another account. diff --git a/src/tests/verified_chats.rs b/src/tests/verified_chats.rs index 131cf4b2a..1851112d6 100644 --- a/src/tests/verified_chats.rs +++ b/src/tests/verified_chats.rs @@ -159,7 +159,7 @@ async fn test_create_verified_oneonone_chat() -> Result<()> { // The chat should be and stay unprotected { - let chat = alice.get_chat(&fiona_new).await.unwrap(); + let chat = alice.get_chat(&fiona_new).await; assert!(!chat.is_protected()); assert!(chat.is_protection_broken()); @@ -287,21 +287,21 @@ async fn test_verified_oneonone_chat_enable_disable() -> Result<()> { ) .await?; - let chat = alice.get_chat(&bob).await.unwrap(); + let chat = alice.get_chat(&bob).await; assert!(!chat.is_protected()); assert!(chat.is_protection_broken()); if alice_accepts_breakage { tcm.section("Alice clicks 'Accept' on the input-bar-dialog"); chat.id.accept(&alice).await?; - let chat = alice.get_chat(&bob).await.unwrap(); + let chat = alice.get_chat(&bob).await; assert!(!chat.is_protected()); assert!(!chat.is_protection_broken()); } // Bob sends a message from DC again tcm.send_recv(&bob, &alice, "Hello from DC").await; - let chat = alice.get_chat(&bob).await.unwrap(); + let chat = alice.get_chat(&bob).await; assert!(chat.is_protected()); assert!(!chat.is_protection_broken()); } @@ -436,7 +436,7 @@ async fn test_old_message_3() -> Result<()> { .await?; alice - .golden_test_chat(alice.get_chat(&bob).await.unwrap().id, "test_old_message_3") + .golden_test_chat(alice.get_chat(&bob).await.id, "test_old_message_3") .await; Ok(()) @@ -636,12 +636,12 @@ async fn test_break_protection_then_verify_again() -> Result<()> { // him as unverified: VerifiedStatus::Unverified ); - let chat = alice.get_chat(&bob_new).await.unwrap(); + let chat = alice.get_chat(&bob_new).await; assert_eq!(chat.is_protected(), false); assert_eq!(chat.is_protection_broken(), true); { - let alice_bob_chat = alice.get_chat(&bob_new).await.unwrap(); + let alice_bob_chat = alice.get_chat(&bob_new).await; assert!(!alice_bob_chat.can_send(&alice).await?); // Alice's UI should still be able to save a draft, which Alice started to type right when she got Bob's message: @@ -706,7 +706,7 @@ async fn assert_verified(this: &TestContext, other: &TestContext, protected: Pro VerifiedStatus::BidirectVerified ); - let chat = this.get_chat(other).await.unwrap(); + let chat = this.get_chat(other).await; let (expect_protected, expect_broken) = match protected { ProtectionStatus::Unprotected => (false, false), ProtectionStatus::Protected => (true, false), From 53f04a134aa0287ee43e579113056c0fa2a665f0 Mon Sep 17 00:00:00 2001 From: Hocuri Date: Tue, 8 Aug 2023 11:35:38 +0200 Subject: [PATCH 043/102] test: Don't accidentally accept that a chat protection is broken (#4550) --- src/chat.rs | 9 ++++++--- src/test_utils.rs | 9 +++++---- src/tests/aeap.rs | 6 +++--- src/tests/verified_chats.rs | 5 ++--- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/chat.rs b/src/chat.rs index 758092b98..9b4af936c 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -398,9 +398,12 @@ impl ChatId { let chat = Chat::load_from_db(context, self).await?; match chat.typ { - Chattype::Single if chat.protected == ProtectionStatus::ProtectionBroken => { - // The chat was in the 'Request' state because the protection was broken. - // The user clicked 'Accept', so, now we want to set the status to Unprotected again: + Chattype::Single + if chat.blocked == Blocked::Not + && chat.protected == ProtectionStatus::ProtectionBroken => + { + // The protection was broken, then the user clicked 'Accept'/'OK', + // so, now we want to set the status to Unprotected again: chat.id .inner_set_protection(context, ProtectionStatus::Unprotected) .await?; diff --git a/src/test_utils.rs b/src/test_utils.rs index 3b31a0ce6..fe02cfa1f 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -27,7 +27,7 @@ use crate::chat::{ }; use crate::chatlist::Chatlist; use crate::config::Config; -use crate::constants::Chattype; +use crate::constants::{Blocked, Chattype}; use crate::constants::{DC_GCL_NO_SPECIALS, DC_MSG_ID_DAYMARKER}; use crate::contact::{Contact, ContactAddress, ContactId, Modifier, Origin}; use crate::context::Context; @@ -119,6 +119,10 @@ impl TestContextManager { msg: &str, ) -> Message { let received_msg = self.send_recv(from, to, msg).await; + assert_eq!( + received_msg.chat_blocked, Blocked::Request, + "`send_recv_accept()` is meant to be used for chat requests. Use `send_recv()` if the chat is already accepted." + ); received_msg.chat_id.accept(to).await.unwrap(); received_msg } @@ -660,7 +664,6 @@ impl TestContext { res } - #[allow(unused)] pub async fn golden_test_chat(&self, chat_id: ChatId, filename: &str) { let filename = Path::new("test-data/golden/").join(filename); @@ -687,8 +690,6 @@ impl TestContext { /// You can use this to debug your test by printing the entire chat conversation. // This code is mainly the same as `log_msglist` in `cmdline.rs`, so one day, we could // merge them to a public function in the `deltachat` crate. - #[allow(dead_code)] - #[allow(clippy::indexing_slicing)] async fn display_chat(&self, chat_id: ChatId) -> String { let mut res = String::new(); diff --git a/src/tests/aeap.rs b/src/tests/aeap.rs index f5f03ba83..db7cedd5f 100644 --- a/src/tests/aeap.rs +++ b/src/tests/aeap.rs @@ -134,11 +134,11 @@ async fn check_aeap_transition( let fiona = tcm.fiona().await; tcm.send_recv_accept(&fiona, &bob, "Hi").await; - tcm.send_recv_accept(&bob, &fiona, "Hi back").await; + tcm.send_recv(&bob, &fiona, "Hi back").await; } tcm.send_recv_accept(&alice, &bob, "Hi").await; - tcm.send_recv_accept(&bob, &alice, "Hi back").await; + tcm.send_recv(&bob, &alice, "Hi back").await; if verified { mark_as_verified(&alice, &bob).await; @@ -355,7 +355,7 @@ async fn test_aeap_replay_attack() -> Result<()> { let bob = tcm.bob().await; tcm.send_recv_accept(&alice, &bob, "Hi").await; - tcm.send_recv_accept(&bob, &alice, "Hi back").await; + tcm.send_recv(&bob, &alice, "Hi back").await; let group = chat::create_group_chat(&bob, chat::ProtectionStatus::Unprotected, "Group 0").await?; diff --git a/src/tests/verified_chats.rs b/src/tests/verified_chats.rs index 1851112d6..cc58dcada 100644 --- a/src/tests/verified_chats.rs +++ b/src/tests/verified_chats.rs @@ -528,8 +528,7 @@ async fn test_outgoing_mua_msg() -> Result<()> { ) .await? .unwrap(); - tcm.send_recv_accept(&alice, &bob, "Sending with DC again") - .await; + tcm.send_recv(&alice, &bob, "Sending with DC again").await; alice .golden_test_chat(sent.chat_id, "test_outgoing_mua_msg") @@ -560,7 +559,7 @@ async fn test_reply() -> Result<()> { } tcm.send_recv_accept(&bob, &alice, "Heyho from DC").await; - let encrypted_msg = tcm.send_recv_accept(&alice, &bob, "Heyho back").await; + let encrypted_msg = tcm.send_recv(&alice, &bob, "Heyho back").await; let unencrypted_msg = receive_imf( &alice, From 03395b95cb49063d8632e23d39ca1ce84fb07ba2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 21:49:54 +0000 Subject: [PATCH 044/102] chore(cargo): bump quick-xml from 0.29.0 to 0.30.0 Bumps [quick-xml](https://github.com/tafia/quick-xml) from 0.29.0 to 0.30.0. - [Release notes](https://github.com/tafia/quick-xml/releases) - [Changelog](https://github.com/tafia/quick-xml/blob/master/Changelog.md) - [Commits](https://github.com/tafia/quick-xml/compare/v0.29.0...v0.30.0) --- updated-dependencies: - dependency-name: quick-xml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8ef89a6e5..0f06078bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3577,9 +3577,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quick-xml" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 0f2554d47..1727e7306 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,7 +69,7 @@ parking_lot = "0.12" pgp = { version = "0.10", default-features = false } pretty_env_logger = { version = "0.5", optional = true } qrcodegen = "1.7.0" -quick-xml = "0.29" +quick-xml = "0.30" rand = "0.8" regex = "1.8" reqwest = { version = "0.11.18", features = ["json"] } From 20c88743dfd8e11c56a4c06e485b9618dc5cdf9d Mon Sep 17 00:00:00 2001 From: iequidoo Date: Tue, 8 Aug 2023 13:52:36 -0300 Subject: [PATCH 045/102] test: W/a message reordering in test_reaction_to_partially_fetched_msg() --- python/tests/test_1_online.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/python/tests/test_1_online.py b/python/tests/test_1_online.py index 0ca45abbf..6cc929bf2 100644 --- a/python/tests/test_1_online.py +++ b/python/tests/test_1_online.py @@ -1467,13 +1467,18 @@ def test_reaction_to_partially_fetched_msg(acfactory, lp, tmp_path): path = tmp_path / "large" path.write_bytes(os.urandom(download_limit + 1)) msgs.append(chat.send_file(str(path))) - - lp.sec("sending a reaction to the large message from ac1 to ac2") - react_str = "\N{THUMBS UP SIGN}" - msgs.append(msgs[-1].send_reaction(react_str)) - for m in msgs: ac1._evtracker.wait_msg_delivered(m) + + lp.sec("sending a reaction to the large message from ac1 to ac2") + # TODO: Find the reason of an occasional message reordering on the server (so that the reaction + # has a lower UID than the previous message). W/a is to sleep for some time to let the reaction + # have a later INTERNALDATE. + time.sleep(1.1) + react_str = "\N{THUMBS UP SIGN}" + msgs.append(msgs[-1].send_reaction(react_str)) + ac1._evtracker.wait_msg_delivered(msgs[-1]) + ac2.start_io() lp.sec("wait for ac2 to receive a reaction") @@ -1505,7 +1510,7 @@ def test_reactions_for_a_reordering_move(acfactory, lp): ac1._evtracker.wait_msg_delivered(msg1) # It's is sad, but messages must differ in their INTERNALDATEs to be processed in the correct # order by DC, and most (if not all) mail servers provide only seconds precision. - time.sleep(2) + time.sleep(1.1) react_str = "\N{THUMBS UP SIGN}" ac1._evtracker.wait_msg_delivered(msg1.send_reaction(react_str)) From 987ce58926837bf86ba7b58588f8c6419d2dbcb0 Mon Sep 17 00:00:00 2001 From: link2xt Date: Fri, 11 Aug 2023 17:06:15 +0000 Subject: [PATCH 046/102] chore(python): fix lint errors --- python/src/deltachat/message.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/src/deltachat/message.py b/python/src/deltachat/message.py index be42b3059..3f813e52d 100644 --- a/python/src/deltachat/message.py +++ b/python/src/deltachat/message.py @@ -510,8 +510,7 @@ def get_viewtype_code_from_name(view_type_name): if code is not None: return code raise ValueError( - "message typecode not found for {!r}, " - "available {!r}".format(view_type_name, list(_view_type_mapping.keys())), + f"message typecode not found for {view_type_name!r}, available {list(_view_type_mapping.keys())!r}", ) From 3b47c3f21daca366d6494d322e9f8ba9264bc448 Mon Sep 17 00:00:00 2001 From: iequidoo Date: Fri, 11 Aug 2023 20:21:04 -0300 Subject: [PATCH 047/102] ci: Run Rust tests with RUST_BACKTRACE set --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 74bec1ea0..48a96f3c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,6 +101,8 @@ jobs: uses: swatinem/rust-cache@v2 - name: Tests + env: + RUST_BACKTRACE: 1 run: cargo test --workspace - name: Test cargo vendor From 16aad3fa67ae95f2aa8094a10083b8c97f2f2009 Mon Sep 17 00:00:00 2001 From: link2xt Date: Thu, 17 Aug 2023 12:20:58 +0000 Subject: [PATCH 048/102] build(cargo-deny): ignore RUSTSEC-2022-0093 It is an API issue that can only be fixed in rPGP and iroh upstream. --- deny.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/deny.toml b/deny.toml index e91ce49d3..a7cf05e12 100644 --- a/deny.toml +++ b/deny.toml @@ -2,6 +2,7 @@ unmaintained = "allow" ignore = [ "RUSTSEC-2020-0071", + "RUSTSEC-2022-0093", ] [bans] From 9094df7bc7c8a0fd1544994ec925f93487f4084d Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 23 Aug 2023 18:20:19 +0000 Subject: [PATCH 049/102] build(python): pin `sphinx` to 7.1.2 --- python/tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/tox.ini b/python/tox.ini index 99fd0c703..0521a23f8 100644 --- a/python/tox.ini +++ b/python/tox.ini @@ -59,7 +59,8 @@ commands = [testenv:doc] changedir=doc deps = - sphinx +# Pinned due to incompatibility of breathe with sphinx 7.2: + sphinx<=7.1.2 breathe commands = sphinx-build -Q -w toxdoc-warnings.log -b html . _build/html From 488a3d1118ade1ccd348c9d69c7e6ef5d0910b89 Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 23 Aug 2023 18:32:16 +0000 Subject: [PATCH 050/102] build(deny): ignore RUSTSEC-2023-0052 --- deny.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/deny.toml b/deny.toml index a7cf05e12..643aae78e 100644 --- a/deny.toml +++ b/deny.toml @@ -3,6 +3,11 @@ unmaintained = "allow" ignore = [ "RUSTSEC-2020-0071", "RUSTSEC-2022-0093", + + # Exponential CPU time usage for TLS certificate processing in webpki. + # It is only used for backup transfer, so does not affect IMAP and SMTP connections. + # Waiting for `iroh` to update dependencies. + "RUSTSEC-2023-0052", ] [bans] From 8f2313bb2a3511111b9f8ebbbee6cbb3c276f81d Mon Sep 17 00:00:00 2001 From: iequidoo Date: Mon, 21 Aug 2023 15:48:12 -0300 Subject: [PATCH 051/102] test: test_openrpc_command_line: Check that deltachat-rpc-server exists with 0 --- deltachat-rpc-client/tests/test_something.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deltachat-rpc-client/tests/test_something.py b/deltachat-rpc-client/tests/test_something.py index b28d2822e..a3bd27d79 100644 --- a/deltachat-rpc-client/tests/test_something.py +++ b/deltachat-rpc-client/tests/test_something.py @@ -363,7 +363,7 @@ async def test_import_export(acfactory, tmp_path) -> None: def test_openrpc_command_line() -> None: """Test that "deltachat-rpc-server --openrpc" command returns an OpenRPC specification.""" - out = subprocess.run(["deltachat-rpc-server", "--openrpc"], capture_output=True).stdout + out = subprocess.run(["deltachat-rpc-server", "--openrpc"], capture_output=True, check=True).stdout openrpc = json.loads(out) assert "openrpc" in openrpc assert "methods" in openrpc From 0179ec2da9a8a402cb2d911610fa0f31f789b42b Mon Sep 17 00:00:00 2001 From: iequidoo Date: Wed, 16 Aug 2023 18:00:43 -0300 Subject: [PATCH 052/102] fix: receive_imf: Update peerstate from db after handling Securejoin handshake (#4600) Otherwise has_verified_encryption() would check a stale Peerstate object. --- python/tests/test_0_complex_or_slow.py | 9 ++++++--- src/receive_imf.rs | 4 ++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/python/tests/test_0_complex_or_slow.py b/python/tests/test_0_complex_or_slow.py index 32d9b82a0..dd49cf8b7 100644 --- a/python/tests/test_0_complex_or_slow.py +++ b/python/tests/test_0_complex_or_slow.py @@ -136,6 +136,7 @@ def test_qr_verified_group_and_chatting(acfactory, lp): lp.sec("ac2: read member added message") msg = ac2._evtracker.wait_next_incoming_message() assert msg.is_encrypted() + assert msg.is_system_message() assert "added" in msg.text.lower() lp.sec("ac1: send message") @@ -182,8 +183,9 @@ def test_qr_verified_group_and_chatting(acfactory, lp): lp.sec("ac2: send message and let ac3 read it") chat2.send_text("hi") - # Skip system message about added member - ac3._evtracker.wait_next_incoming_message() + # System message about the added member. + msg = ac3._evtracker.wait_next_incoming_message() + assert msg.is_system_message() msg = ac3._evtracker.wait_next_incoming_message() assert msg.text == "hi" assert msg.is_encrypted() @@ -524,7 +526,8 @@ def test_see_new_verified_member_after_going_online(acfactory, tmp_path, lp): lp.sec("ac2: sending message") # Message can be sent only after a receipt of "vg-member-added" message. Just wait for # "Member Me () added by ." message. - ac2._evtracker.wait_next_incoming_message() + msg_in = ac2._evtracker.wait_next_incoming_message() + assert msg_in.is_system_message() msg_out = chat2.send_text("hello") lp.sec("ac1: receiving message") diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 818b850fd..7547e49ab 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -516,6 +516,10 @@ async fn add_parts( securejoin_seen = true; } } + // Peerstate could be updated by handling the Securejoin handshake. + let contact = Contact::get_by_id(context, from_id).await?; + mime_parser.decryption_info.peerstate = + Peerstate::from_addr(context, contact.get_addr()).await?; } else { securejoin_seen = false; } From 95b2a159303c3f36b91ad7936b224c826d3a4871 Mon Sep 17 00:00:00 2001 From: iequidoo Date: Wed, 16 Aug 2023 22:59:46 -0300 Subject: [PATCH 053/102] fix: Sort old incoming messages below all outgoing ones (#4621) If the Inbox is fetched before the Sentbox (as done currently), messages from the Sentbox will correctly mingle with the Inbox messages in the end. So, this commit changes message ordering only if we already have processed outgoing messages, e.g. if we just sent them in the chat as described in #4621. Otherwise new incoming messages are displayed somewhere in the middle of the chat which doesn't look usable. --- src/receive_imf.rs | 16 +++++++----- src/tests/verified_chats.rs | 40 +++++++++++++++++++++++++++++ test-data/golden/test_old_message_5 | 5 ++++ 3 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 test-data/golden/test_old_message_5 diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 7547e49ab..4a9d8311b 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -1400,17 +1400,19 @@ async fn calc_sort_timestamp( ) .await? } else if incoming { - // get newest incoming non fresh message for this chat. + // get newest non fresh message for this chat. - // If a user hasn't been online for some time, the Inbox is - // fetched first and then the Sentbox. In order for Inbox - // and Sent messages to be allowed to mingle, - // outgoing messages are purely sorted by their sent timestamp. + // If a user hasn't been online for some time, the Inbox is fetched first and then the + // Sentbox. In order for Inbox and Sent messages to be allowed to mingle, outgoing messages + // are purely sorted by their sent timestamp. NB: The Inbox must be fetched first otherwise + // Inbox messages would be always below old Sentbox messages. We could take in the query + // below only incoming messages, but then new incoming messages would mingle with just sent + // outgoing ones and apear somewhere in the middle of the chat. context .sql .query_get_value( - "SELECT MAX(timestamp) FROM msgs WHERE chat_id=? AND state>? AND from_id!=?", - (chat_id, MessageState::InFresh, ContactId::SELF), + "SELECT MAX(timestamp) FROM msgs WHERE chat_id=? AND state>?", + (chat_id, MessageState::InFresh), ) .await? } else { diff --git a/src/tests/verified_chats.rs b/src/tests/verified_chats.rs index cc58dcada..202bd11d4 100644 --- a/src/tests/verified_chats.rs +++ b/src/tests/verified_chats.rs @@ -480,6 +480,46 @@ async fn test_old_message_4() -> Result<()> { Ok(()) } +/// Alice is offline for some time. +/// When they come online, first their sentbox is synced and then their inbox. +/// This test tests that the messages are still in the right order. +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_old_message_5() -> Result<()> { + let alice = TestContext::new_alice().await; + let msg_sent = receive_imf( + &alice, + b"From: alice@example.org\n\ + To: Bob \n\ + Message-ID: <1234-2-4@example.org>\n\ + Date: Sat, 07 Dec 2019 19:00:27 +0000\n\ + \n\ + Happy birthday, Bob!\n", + true, + ) + .await? + .unwrap(); + + let msg_incoming = receive_imf( + &alice, + b"From: Bob \n\ + To: alice@example.org\n\ + Message-ID: <1234-2-3@example.org>\n\ + Date: Sun, 07 Dec 2019 19:00:26 +0000\n\ + \n\ + Happy birthday to me, Alice!\n", + false, + ) + .await? + .unwrap(); + + assert!(msg_sent.sort_timestamp == msg_incoming.sort_timestamp); + alice + .golden_test_chat(msg_sent.chat_id, "test_old_message_5") + .await; + + Ok(()) +} + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mdn_doesnt_disable_verification() -> Result<()> { let mut tcm = TestContextManager::new(); diff --git a/test-data/golden/test_old_message_5 b/test-data/golden/test_old_message_5 new file mode 100644 index 000000000..75d3c0af0 --- /dev/null +++ b/test-data/golden/test_old_message_5 @@ -0,0 +1,5 @@ +Single#Chat#10: Bob [bob@example.net] +-------------------------------------------------------------------------------- +Msg#10: Me (Contact#Contact#Self): Happy birthday, Bob! √ +Msg#11: (Contact#Contact#10): Happy birthday to me, Alice! [FRESH] +-------------------------------------------------------------------------------- From a66f8bd9fc1baf37e5a8229f084d1e410ace76b5 Mon Sep 17 00:00:00 2001 From: iequidoo Date: Wed, 9 Aug 2023 18:14:24 -0300 Subject: [PATCH 054/102] fix: Delete messages from SMTP queue only on user demand (#4579) I.e. from delete_msgs(). Otherwise messages must not be deleted from there, e.g. if a message is ephemeral, but a network outage lasts longer than the ephemeral message timer, the message still must be sent upon a successful reconnection. --- src/ephemeral.rs | 33 ++++++++++++++++++++++++++--- src/message.rs | 55 ++++++++++++++++++++++++++++-------------------- src/smtp.rs | 18 ---------------- 3 files changed, 62 insertions(+), 44 deletions(-) diff --git a/src/ephemeral.rs b/src/ephemeral.rs index 6d200b99b..694c1d41c 100644 --- a/src/ephemeral.rs +++ b/src/ephemeral.rs @@ -1062,14 +1062,14 @@ mod tests { delete_expired_messages(t, not_deleted_at).await?; let loaded = Message::load_from_db(t, msg_id).await?; - assert_eq!(loaded.text, "Message text"); + assert!(!loaded.text.is_empty()); assert_eq!(loaded.chat_id, chat.id); assert!(next_expiration < deleted_at); delete_expired_messages(t, deleted_at).await?; t.evtracker .get_matching(|evt| { - if let EventType::MsgsChanged { + if let EventType::MsgDeleted { msg_id: event_msg_id, .. } = evt @@ -1082,7 +1082,6 @@ mod tests { .await; let loaded = Message::load_from_db(t, msg_id).await?; - assert_eq!(loaded.text, ""); assert_eq!(loaded.chat_id, DC_CHAT_ID_TRASH); // Check that the msg was deleted locally. @@ -1300,4 +1299,32 @@ mod tests { Ok(()) } + + // Tests that if we are offline for a time longer than the ephemeral timer duration, the message + // is deleted from the chat but is still in the "smtp" table, i.e. will be sent upon a + // successful reconnection. + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_ephemeral_msg_offline() -> Result<()> { + let alice = TestContext::new_alice().await; + let chat = alice + .create_chat_with_contact("Bob", "bob@example.org") + .await; + let duration = 60; + chat.id + .set_ephemeral_timer(&alice, Timer::Enabled { duration }) + .await?; + let mut msg = Message::new(Viewtype::Text); + msg.set_text("hi".to_string()); + assert!(chat::send_msg_sync(&alice, chat.id, &mut msg) + .await + .is_err()); + let stmt = "SELECT COUNT(*) FROM smtp WHERE msg_id=?"; + assert!(alice.sql.exists(stmt, (msg.id,)).await?); + let now = time(); + check_msg_will_be_deleted(&alice, msg.id, &chat, now, now + i64::from(duration) + 1) + .await?; + assert!(alice.sql.exists(stmt, (msg.id,)).await?); + + Ok(()) + } } diff --git a/src/message.rs b/src/message.rs index d79208a8e..4ebc46790 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1421,6 +1421,7 @@ pub async fn get_mime_headers(context: &Context, msg_id: MsgId) -> Result Result<()> { let mut modified_chat_ids = BTreeSet::new(); + let mut res = Ok(()); for &msg_id in msg_ids { let msg = Message::load_from_db(context, msg_id).await?; @@ -1444,13 +1445,19 @@ pub async fn delete_msgs(context: &Context, msg_ids: &[MsgId]) -> Result<()> { modified_chat_ids.insert(msg.chat_id); let target = context.get_delete_msgs_target().await?; - context - .sql - .execute( + let update_db = |conn: &mut rusqlite::Connection| { + conn.execute( "UPDATE imap SET target=? WHERE rfc724_mid=?", (target, msg.rfc724_mid), - ) - .await?; + )?; + conn.execute("DELETE FROM smtp WHERE msg_id=?", (msg_id,))?; + Ok(()) + }; + if let Err(e) = context.sql.call_write(update_db).await { + error!(context, "delete_msgs: failed to update db: {e:#}."); + res = Err(e); + continue; + } let logging_xdc_id = context .debug_logging @@ -1465,6 +1472,7 @@ pub async fn delete_msgs(context: &Context, msg_ids: &[MsgId]) -> Result<()> { } } } + res?; for modified_chat_id in modified_chat_ids { context.emit_msgs_changed(modified_chat_id, MsgId::new(0)); @@ -1633,24 +1641,6 @@ pub(crate) async fn update_msg_state( // Context functions to work with messages -/// Returns true if given message ID exists in the database and is not trashed. -pub(crate) async fn exists(context: &Context, msg_id: MsgId) -> Result { - if msg_id.is_special() { - return Ok(false); - } - - let chat_id: Option = context - .sql - .query_get_value("SELECT chat_id FROM msgs WHERE id=?;", (msg_id,)) - .await?; - - if let Some(chat_id) = chat_id { - Ok(!chat_id.is_trash()) - } else { - Ok(false) - } -} - pub(crate) async fn set_msg_failed(context: &Context, msg_id: MsgId, error: &str) { if let Ok(mut msg) = Message::load_from_db(context, msg_id).await { if msg.state.can_fail() { @@ -2422,4 +2412,23 @@ def hello(): Ok(()) } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_delete_msgs_offline() -> Result<()> { + let alice = TestContext::new_alice().await; + let chat = alice + .create_chat_with_contact("Bob", "bob@example.org") + .await; + let mut msg = Message::new(Viewtype::Text); + msg.set_text("hi".to_string()); + assert!(chat::send_msg_sync(&alice, chat.id, &mut msg) + .await + .is_err()); + let stmt = "SELECT COUNT(*) FROM smtp WHERE msg_id=?"; + assert!(alice.sql.exists(stmt, (msg.id,)).await?); + delete_msgs(&alice, &[msg.id]).await?; + assert!(!alice.sql.exists(stmt, (msg.id,)).await?); + + Ok(()) + } } diff --git a/src/smtp.rs b/src/smtp.rs index d01d00926..5195826a0 100644 --- a/src/smtp.rs +++ b/src/smtp.rs @@ -566,24 +566,6 @@ pub(crate) async fn send_msg_to_smtp( ) .collect::>(); - // If there is a msg-id and it does not exist in the db, cancel sending. this happens if - // delete_msgs() was called before the generated mime was sent out. - if !message::exists(context, msg_id) - .await - .with_context(|| format!("failed to check message {msg_id} existence"))? - { - info!( - context, - "Sending of message {msg_id} (entry {rowid}) was cancelled by the user." - ); - context - .sql - .execute("DELETE FROM smtp WHERE id=?", (rowid,)) - .await - .context("failed to remove cancelled message from smtp table")?; - return Ok(()); - } - let status = smtp_send(context, &recipients_list, body.as_str(), smtp, msg_id).await; match status { From 8c778b3f5c163e7522c99b01fde1e5b64343d4e0 Mon Sep 17 00:00:00 2001 From: link2xt Date: Thu, 24 Aug 2023 01:31:36 +0000 Subject: [PATCH 055/102] test: extend `test_qr_join_chat` to check that the group is not verified --- python/tests/test_1_online.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/python/tests/test_1_online.py b/python/tests/test_1_online.py index 6cc929bf2..160422211 100644 --- a/python/tests/test_1_online.py +++ b/python/tests/test_1_online.py @@ -9,7 +9,7 @@ import pytest from imap_tools import AND, U import deltachat as dc -from deltachat import account_hookimpl, Message +from deltachat import account_hookimpl, Message, Chat from deltachat.tracker import ImexTracker @@ -1669,8 +1669,12 @@ def test_qr_setup_contact(acfactory, lp): ac1._evtracker.wait_securejoin_inviter_progress(1000) -def test_qr_join_chat(acfactory, lp): +@pytest.mark.parametrize("verified_one_on_one_chats", [0, 1]) +def test_qr_join_chat(acfactory, lp, verified_one_on_one_chats): ac1, ac2 = acfactory.get_online_accounts(2) + ac1.set_config("verified_one_on_one_chats", verified_one_on_one_chats) + ac2.set_config("verified_one_on_one_chats", verified_one_on_one_chats) + lp.sec("ac1: create QR code and let ac2 scan it, starting the securejoin") chat = ac1.create_group_chat("hello") qr = chat.get_join_qr() @@ -1683,6 +1687,17 @@ def test_qr_join_chat(acfactory, lp): ac2._evtracker.get_matching("DC_EVENT_IMAP_MESSAGE_DELETED") ac1._evtracker.wait_securejoin_inviter_progress(1000) + msg = ac2._evtracker.wait_next_incoming_message() + assert msg.text == "Member Me ({}) added by {}.".format(ac2.get_config("addr"), ac1.get_config("addr")) + + # ac1 reloads the chat. + chat = Chat(chat.account, chat.id) + assert not chat.is_protected() + + # ac2 reloads the chat. + ch = Chat(ch.account, ch.id) + assert not ch.is_protected() + def test_qr_email_capitalization(acfactory, lp): """Regression test for a bug From 7676473ebd5356c071642642cd887938b9bb394b Mon Sep 17 00:00:00 2001 From: link2xt Date: Thu, 24 Aug 2023 01:49:39 +0000 Subject: [PATCH 056/102] fix: do not mark non-verified group chats as verified when using securejoin Only mark the chat is verified if 1:1 verified chats are enabled and securejoin targets a 1:1 chat. --- src/receive_imf.rs | 16 ++++++++++++++++ src/securejoin.rs | 35 +++++++++++++++++++++++++---------- src/securejoin/bob.rs | 25 +++++++++++++++++-------- 3 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 4a9d8311b..e8f6afe67 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -1731,6 +1731,22 @@ async fn apply_group_changes( false }; + if mime_parser.get_header(HeaderDef::ChatVerified).is_some() { + if let VerifiedEncryption::NotVerified(err) = + has_verified_encryption(context, mime_parser, from_id, to_ids, chat.typ).await? + { + warn!(context, "Verification problem: {err:#}."); + let s = format!("{err}. See 'Info' for more details"); + mime_parser.repl_msg_by_error(&s); + } + + if !chat.is_protected() { + chat_id + .inner_set_protection(context, ProtectionStatus::Protected) + .await?; + } + } + if let Some(removed_addr) = mime_parser.get_header(HeaderDef::ChatGroupMemberRemoved) { removed_id = Contact::lookup_id_by_addr(context, removed_addr, Origin::Unknown).await?; diff --git a/src/securejoin.rs b/src/securejoin.rs index 34de7b658..df045ad4c 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -8,7 +8,7 @@ use percent_encoding::{utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC}; use crate::aheader::EncryptPreference; use crate::chat::{self, Chat, ChatId, ChatIdBlocked, ProtectionStatus}; use crate::config::Config; -use crate::constants::Blocked; +use crate::constants::{Blocked, Chattype}; use crate::contact::{Contact, ContactId, Origin, VerifiedStatus}; use crate::context::Context; use crate::e2ee::ensure_secret_key_exists; @@ -701,14 +701,22 @@ async fn secure_connection_established( let contact = Contact::get_by_id(context, contact_id).await?; let msg = stock_str::contact_verified(context, &contact).await; chat::add_info_msg(context, chat_id, &msg, time()).await?; - chat_id - .set_protection( - context, - ProtectionStatus::Protected, - time(), - Some(contact_id), - ) - .await?; + if context + .get_config_bool(Config::VerifiedOneOnOneChats) + .await? + { + let chat = Chat::load_from_db(context, chat_id).await?; + if chat.typ == Chattype::Single { + chat_id + .set_protection( + context, + ProtectionStatus::Protected, + time(), + Some(contact_id), + ) + .await?; + } + } context.emit_event(EventType::ChatModified(chat_id)); Ok(()) } @@ -786,7 +794,6 @@ mod tests { use crate::chat; use crate::chat::ProtectionStatus; use crate::chatlist::Chatlist; - use crate::constants::Chattype; use crate::contact::ContactAddress; use crate::contact::VerifiedStatus; use crate::peerstate::Peerstate; @@ -801,6 +808,14 @@ mod tests { let mut tcm = TestContextManager::new(); let alice = tcm.alice().await; let bob = tcm.bob().await; + alice + .set_config(Config::VerifiedOneOnOneChats, Some("1")) + .await + .unwrap(); + bob.set_config(Config::VerifiedOneOnOneChats, Some("1")) + .await + .unwrap(); + assert_eq!( Chatlist::try_load(&alice, 0, None, None) .await diff --git a/src/securejoin/bob.rs b/src/securejoin/bob.rs index c824a5367..73903e2ce 100644 --- a/src/securejoin/bob.rs +++ b/src/securejoin/bob.rs @@ -9,6 +9,7 @@ use super::bobstate::{BobHandshakeStage, BobState}; use super::qrinvite::QrInvite; use super::HandshakeMessage; use crate::chat::{is_contact_in_chat, ChatId, ProtectionStatus}; +use crate::config::Config; use crate::constants::{Blocked, Chattype}; use crate::contact::Contact; use crate::context::Context; @@ -222,14 +223,22 @@ impl BobState { let msg = stock_str::contact_verified(context, &contact).await; let chat_id = self.joining_chat_id(context).await?; chat::add_info_msg(context, chat_id, &msg, time()).await?; - chat_id - .set_protection( - context, - ProtectionStatus::Protected, - time(), - Some(contact.id), - ) - .await?; + + if context + .get_config_bool(Config::VerifiedOneOnOneChats) + .await? + && chat_id == self.alice_chat() + { + chat_id + .set_protection( + context, + ProtectionStatus::Protected, + time(), + Some(contact.id), + ) + .await?; + } + context.emit_event(EventType::ChatModified(chat_id)); Ok(()) } From 94cd9a713f8dd4f055168fe71cb4f33c76327ecf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Aug 2023 18:42:54 +0000 Subject: [PATCH 057/102] chore(cargo): bump sanitize-filename from 0.4.0 to 0.5.0 Bumps [sanitize-filename](https://github.com/kardeiz/sanitize-filename) from 0.4.0 to 0.5.0. - [Commits](https://github.com/kardeiz/sanitize-filename/commits) --- updated-dependencies: - dependency-name: sanitize-filename dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- deltachat-jsonrpc/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f06078bc..944ffb8a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4130,9 +4130,9 @@ dependencies = [ [[package]] name = "sanitize-filename" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c502bdb638f1396509467cb0580ef3b29aa2a45c5d43e5d84928241280296c" +checksum = "2ed72fbaf78e6f2d41744923916966c4fbe3d7c74e3037a8ee482f1115572603" dependencies = [ "lazy_static", "regex", diff --git a/Cargo.toml b/Cargo.toml index 1727e7306..e6496786f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,7 +75,7 @@ regex = "1.8" reqwest = { version = "0.11.18", features = ["json"] } rusqlite = { version = "0.29", features = ["sqlcipher"] } rust-hsluv = "0.1" -sanitize-filename = "0.4" +sanitize-filename = "0.5" serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } sha-1 = "0.10" diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index 06b00a108..c511c3489 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -25,7 +25,7 @@ serde_json = "1.0.99" yerpc = { version = "0.5.2", features = ["anyhow_expose", "openrpc"] } typescript-type-def = { version = "0.5.5", features = ["json_value"] } tokio = { version = "1.29.1" } -sanitize-filename = "0.4" +sanitize-filename = "0.5" walkdir = "2.3.3" base64 = "0.21" From 95f29f7b637f5aa898b69ce39663fecf4c9a7e93 Mon Sep 17 00:00:00 2001 From: iequidoo Date: Thu, 24 Aug 2023 14:54:14 -0300 Subject: [PATCH 058/102] fix: receive_imf: Set protection only for Chattype::Single (#4597) Also don't set protection to ProtectionBroken if it already is. Co-authored-by: Hocuri --- src/receive_imf.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/receive_imf.rs b/src/receive_imf.rs index e8f6afe67..95fbfb03a 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -728,12 +728,17 @@ async fn add_parts( } } - // The next block checks if the message was sent with verified encryption - // and sets the protection of the 1:1 chat accordingly. - if is_partial_download.is_none() + // Check if the message was sent with verified encryption and set the protection of + // the 1:1 chat accordingly. + let chat = match is_partial_download.is_none() && mime_parser.get_header(HeaderDef::SecureJoin).is_none() && !is_mdn { + true => Some(Chat::load_from_db(context, chat_id).await?) + .filter(|chat| chat.typ == Chattype::Single), + false => None, + }; + if let Some(chat) = chat { let mut new_protection = match has_verified_encryption( context, mime_parser, @@ -747,17 +752,15 @@ async fn add_parts( VerifiedEncryption::NotVerified(_) => ProtectionStatus::Unprotected, }; - let chat = Chat::load_from_db(context, chat_id).await?; - + if chat.protected != ProtectionStatus::Unprotected + && new_protection == ProtectionStatus::Unprotected + // `chat.protected` must be maintained regardless of the `Config::VerifiedOneOnOneChats`. + // That's why the config is checked here, and not above. + && context.get_config_bool(Config::VerifiedOneOnOneChats).await? + { + new_protection = ProtectionStatus::ProtectionBroken; + } if chat.protected != new_protection { - if new_protection == ProtectionStatus::Unprotected - && context - .get_config_bool(Config::VerifiedOneOnOneChats) - .await? - { - new_protection = ProtectionStatus::ProtectionBroken; - } - // The message itself will be sorted under the device message since the device // message is `MessageState::InNoticed`, which means that all following // messages are sorted under it. From a520f0268fe95f3d9db572108882ac0cf014b2c1 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 26 Aug 2023 18:15:11 +0000 Subject: [PATCH 059/102] chore: rustfmt --- src/receive_imf.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 95fbfb03a..0ed1aa6fd 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -2214,7 +2214,9 @@ async fn has_verified_encryption( // and results in group-splits otherwise. if from_id != ContactId::SELF { let Some(peerstate) = &mimeparser.decryption_info.peerstate else { - return Ok(NotVerified("No peerstate, the contact isn't verified".to_string())); + return Ok(NotVerified( + "No peerstate, the contact isn't verified".to_string(), + )); }; if !peerstate.has_verified_key(&mimeparser.signatures) { From 83ef25e7de9c5f2ba8bbe544964aa6f7a96aaf3f Mon Sep 17 00:00:00 2001 From: iequidoo Date: Fri, 11 Aug 2023 12:35:55 -0300 Subject: [PATCH 060/102] fix: Return from dc_get_chatlist(DC_GCL_FOR_FORWARDING) only chats where we can send (#4616) I.e. exclude from the list the following chats as well: - Read-only mailing lists. - Chats we're not a member of. But as for ProtectionBroken chats, we return them, as that may happen to a verified chat at any time. It may be confusing if a chat that is normally in the list disappears suddenly. The UI need to deal with that case anyway. --- src/chat.rs | 3 +- src/chatlist.rs | 114 ++++++++++++++++++++++++++++-------- src/receive_imf/tests.rs | 4 +- src/tests/verified_chats.rs | 6 ++ 4 files changed, 99 insertions(+), 28 deletions(-) diff --git a/src/chat.rs b/src/chat.rs index ed2c03cfe..ef30b7393 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1255,6 +1255,7 @@ impl Chat { pub(crate) async fn why_cant_send(&self, context: &Context) -> Result> { use CantSendReason::*; + // NB: Don't forget to update Chatlist::try_load() when changing this function! let reason = if self.id.is_special() { Some(SpecialChat) } else if self.is_device_talk() { @@ -1263,7 +1264,7 @@ impl Chat { Some(ContactRequest) } else if self.is_protection_broken() { Some(ProtectionBroken) - } else if self.is_mailing_list() && self.param.get(Param::ListPost).is_none_or_empty() { + } else if self.is_mailing_list() && self.get_mailinglist_addr().is_none_or_empty() { Some(ReadOnlyMailingList) } else if !self.is_self_in_chat(context).await? { Some(NotAMember) diff --git a/src/chatlist.rs b/src/chatlist.rs index da817e05a..beafa1206 100644 --- a/src/chatlist.rs +++ b/src/chatlist.rs @@ -10,8 +10,10 @@ use crate::constants::{ use crate::contact::{Contact, ContactId}; use crate::context::Context; use crate::message::{Message, MessageState, MsgId}; +use crate::param::{Param, Params}; use crate::stock_str; use crate::summary::Summary; +use crate::tools::IsNoneOrEmpty; /// An object representing a single chatlist in memory. /// @@ -204,34 +206,84 @@ impl Chatlist { ) .await? } else { - // show normal chatlist - let sort_id_up = if flag_for_forwarding { - ChatId::lookup_by_contact(context, ContactId::SELF) + let mut ids = if flag_for_forwarding { + let sort_id_up = ChatId::lookup_by_contact(context, ContactId::SELF) .await? - .unwrap_or_default() + .unwrap_or_default(); + let process_row = |row: &rusqlite::Row| { + let chat_id: ChatId = row.get(0)?; + let typ: Chattype = row.get(1)?; + let param: Params = row.get::<_, String>(2)?.parse().unwrap_or_default(); + let msg_id: Option = row.get(3)?; + Ok((chat_id, typ, param, msg_id)) + }; + let process_rows = |rows: rusqlite::MappedRows<_>| { + rows.filter_map(|row: std::result::Result<(_, _, Params, _), _>| match row { + Ok((chat_id, typ, param, msg_id)) => { + if typ == Chattype::Mailinglist + && param.get(Param::ListPost).is_none_or_empty() + { + None + } else { + Some(Ok((chat_id, msg_id))) + } + } + Err(e) => Some(Err(e)), + }) + .collect::, _>>() + .map_err(Into::into) + }; + // Return ProtectionBroken chats also, as that may happen to a verified chat at any + // time. It may be confusing if a chat that is normally in the list disappears + // suddenly. The UI need to deal with that case anyway. + context.sql.query_map( + "SELECT c.id, c.type, c.param, m.id + FROM chats c + LEFT JOIN msgs m + ON c.id=m.chat_id + AND m.id=( + SELECT id + FROM msgs + WHERE chat_id=c.id + AND (hidden=0 OR state=?) + ORDER BY timestamp DESC, id DESC LIMIT 1) + WHERE c.id>9 AND c.id!=? + AND c.blocked=0 + AND NOT c.archived=? + AND (c.type!=? OR c.id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?)) + GROUP BY c.id + ORDER BY c.id=? DESC, c.archived=? DESC, IFNULL(m.timestamp,c.created_timestamp) DESC, m.id DESC;", + ( + MessageState::OutDraft, skip_id, ChatVisibility::Archived, + Chattype::Group, ContactId::SELF, + sort_id_up, ChatVisibility::Pinned, + ), + process_row, + process_rows, + ).await? } else { - ChatId::new(0) + // show normal chatlist + context.sql.query_map( + "SELECT c.id, m.id + FROM chats c + LEFT JOIN msgs m + ON c.id=m.chat_id + AND m.id=( + SELECT id + FROM msgs + WHERE chat_id=c.id + AND (hidden=0 OR state=?) + ORDER BY timestamp DESC, id DESC LIMIT 1) + WHERE c.id>9 AND c.id!=? + AND (c.blocked=0 OR c.blocked=2) + AND NOT c.archived=? + GROUP BY c.id + ORDER BY c.id=0 DESC, c.archived=? DESC, IFNULL(m.timestamp,c.created_timestamp) DESC, m.id DESC;", + (MessageState::OutDraft, skip_id, ChatVisibility::Archived, ChatVisibility::Pinned), + process_row, + process_rows, + ).await? }; - let mut ids = context.sql.query_map( - "SELECT c.id, m.id - FROM chats c - LEFT JOIN msgs m - ON c.id=m.chat_id - AND m.id=( - SELECT id - FROM msgs - WHERE chat_id=c.id - AND (hidden=0 OR state=?1) - ORDER BY timestamp DESC, id DESC LIMIT 1) - WHERE c.id>9 AND c.id!=?2 - AND (c.blocked=0 OR (c.blocked=2 AND NOT ?3)) - AND NOT c.archived=?4 - GROUP BY c.id - ORDER BY c.id=?5 DESC, c.archived=?6 DESC, IFNULL(m.timestamp,c.created_timestamp) DESC, m.id DESC;", - (MessageState::OutDraft, skip_id, flag_for_forwarding, ChatVisibility::Archived, sort_id_up, ChatVisibility::Pinned), - process_row, - process_rows, - ).await?; if !flag_no_specials && get_archived_cnt(context).await? > 0 { if ids.is_empty() && flag_add_alldone_hint { ids.push((DC_CHAT_ID_ALLDONE_HINT, None)); @@ -388,7 +440,9 @@ pub async fn get_last_message_for_chat( #[cfg(test)] mod tests { use super::*; - use crate::chat::{create_group_chat, get_chat_contacts, ProtectionStatus}; + use crate::chat::{ + create_group_chat, get_chat_contacts, remove_contact_from_chat, ProtectionStatus, + }; use crate::message::Viewtype; use crate::receive_imf::receive_imf; use crate::stock_str::StockMessage; @@ -473,6 +527,14 @@ mod tests { .await .unwrap() .is_self_talk()); + + remove_contact_from_chat(&t, chats.get_chat_id(1).unwrap(), ContactId::SELF) + .await + .unwrap(); + let chats = Chatlist::try_load(&t, DC_GCL_FOR_FORWARDING, None, None) + .await + .unwrap(); + assert!(chats.len() == 1); } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] diff --git a/src/receive_imf/tests.rs b/src/receive_imf/tests.rs index 041ed20a0..2db8df963 100644 --- a/src/receive_imf/tests.rs +++ b/src/receive_imf/tests.rs @@ -8,7 +8,7 @@ use crate::chat::{ }; use crate::chat::{get_chat_msgs, ChatItem, ChatVisibility}; use crate::chatlist::Chatlist; -use crate::constants::DC_GCL_NO_SPECIALS; +use crate::constants::{DC_GCL_FOR_FORWARDING, DC_GCL_NO_SPECIALS}; use crate::imap::prefetch_should_download; use crate::message::Message; use crate::test_utils::{get_chat_msg, TestContext, TestContextManager}; @@ -793,6 +793,8 @@ async fn test_github_mailing_list() -> Result<()> { let chats = Chatlist::try_load(&t.ctx, 0, None, None).await?; assert_eq!(chats.len(), 1); + let chats = Chatlist::try_load(&t.ctx, DC_GCL_FOR_FORWARDING, None, None).await?; + assert_eq!(chats.len(), 0); let contacts = Contact::get_all(&t.ctx, 0, None).await?; assert_eq!(contacts.len(), 0); // mailing list recipients and senders do not count as "known contacts" diff --git a/src/tests/verified_chats.rs b/src/tests/verified_chats.rs index 202bd11d4..413338929 100644 --- a/src/tests/verified_chats.rs +++ b/src/tests/verified_chats.rs @@ -2,7 +2,9 @@ use anyhow::Result; use pretty_assertions::assert_eq; use crate::chat::{Chat, ProtectionStatus}; +use crate::chatlist::Chatlist; use crate::config::Config; +use crate::constants::DC_GCL_FOR_FORWARDING; use crate::contact::VerifiedStatus; use crate::contact::{Contact, Origin}; use crate::message::{Message, Viewtype}; @@ -657,6 +659,8 @@ async fn test_break_protection_then_verify_again() -> Result<()> { alice.create_chat(&bob).await; assert_verified(&alice, &bob, ProtectionStatus::Protected).await; + let chats = Chatlist::try_load(&alice, DC_GCL_FOR_FORWARDING, None, None).await?; + assert!(chats.len() == 1); tcm.section("Bob reinstalls DC"); drop(bob); @@ -678,6 +682,8 @@ async fn test_break_protection_then_verify_again() -> Result<()> { let chat = alice.get_chat(&bob_new).await; assert_eq!(chat.is_protected(), false); assert_eq!(chat.is_protection_broken(), true); + let chats = Chatlist::try_load(&alice, DC_GCL_FOR_FORWARDING, None, None).await?; + assert!(chats.len() == 1); { let alice_bob_chat = alice.get_chat(&bob_new).await; From 60ddbe57292b2041896ce31d0920c307f2b866cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 21:09:22 +0000 Subject: [PATCH 061/102] chore(cargo): bump strum_macros from 0.25.1 to 0.25.2 Bumps [strum_macros](https://github.com/Peternator7/strum) from 0.25.1 to 0.25.2. - [Changelog](https://github.com/Peternator7/strum/blob/master/CHANGELOG.md) - [Commits](https://github.com/Peternator7/strum/commits) --- updated-dependencies: - dependency-name: strum_macros dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07fd501c4..3596bda62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4567,9 +4567,9 @@ checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" [[package]] name = "strum_macros" -version = "0.25.1" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6069ca09d878a33f883cc06aaa9718ede171841d3832450354410b718b097232" +checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" dependencies = [ "heck", "proc-macro2", From 6881f9d70f2bb0b7ae31de262614d0b7b924994b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 21:10:52 +0000 Subject: [PATCH 062/102] chore(cargo): bump syn from 2.0.28 to 2.0.29 Bumps [syn](https://github.com/dtolnay/syn) from 2.0.28 to 2.0.29. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.28...2.0.29) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07fd501c4..fa8bd3445 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -276,7 +276,7 @@ checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -987,7 +987,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -1221,7 +1221,7 @@ name = "deltachat_derive" version = "2.0.0" dependencies = [ "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -1427,7 +1427,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -1727,7 +1727,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -2030,7 +2030,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -2949,7 +2949,7 @@ checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -3063,7 +3063,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -3300,7 +3300,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -4268,7 +4268,7 @@ checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -4575,7 +4575,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -4597,9 +4597,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" dependencies = [ "proc-macro2", "quote", @@ -4729,7 +4729,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -4844,7 +4844,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -5007,7 +5007,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -5340,7 +5340,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", "wasm-bindgen-shared", ] @@ -5374,7 +5374,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5777,5 +5777,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] From 88ae653760fc4417fd5f0b728fba0e9f7521d0e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 21:11:10 +0000 Subject: [PATCH 063/102] chore(cargo): bump chrono from 0.4.26 to 0.4.28 Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.26 to 0.4.28. - [Release notes](https://github.com/chronotope/chrono/releases) - [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md) - [Commits](https://github.com/chronotope/chrono/compare/v0.4.26...v0.4.28) --- updated-dependencies: - dependency-name: chrono dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fa8bd3445..088748217 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -643,9 +643,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f" dependencies = [ "android-tzdata", "iana-time-zone", @@ -653,7 +653,7 @@ dependencies = [ "num-traits", "time 0.1.45", "wasm-bindgen", - "winapi", + "windows-targets 0.48.1", ] [[package]] From 99302c9598a3ff467e95957f1ad3f912fb341f8b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 21:07:36 +0000 Subject: [PATCH 064/102] chore(cargo): bump base64 from 0.21.2 to 0.21.3 Bumps [base64](https://github.com/marshallpierce/rust-base64) from 0.21.2 to 0.21.3. - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.21.2...v0.21.3) --- updated-dependencies: - dependency-name: base64 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 088748217..9efe2628b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,7 +215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b538b767cbf9c162a6c5795d4b932bd2c20ba10b5a91a94d2b2b6886c1dce6a8" dependencies = [ "async-channel", - "base64 0.21.2", + "base64 0.21.3", "bytes", "chrono", "futures", @@ -307,7 +307,7 @@ checksum = "a6a1de45611fdb535bfde7b7de4fd54f4fd2b17b1737c0a59b69bf9b92074b8c" dependencies = [ "async-trait", "axum-core", - "base64 0.21.2", + "base64 0.21.3", "bitflags 1.3.2", "bytes", "futures-util", @@ -398,9 +398,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" [[package]] name = "base64ct" @@ -1095,7 +1095,7 @@ dependencies = [ "async-smtp", "async_zip", "backtrace", - "base64 0.21.2", + "base64 0.21.3", "brotli", "chrono", "criterion", @@ -1167,7 +1167,7 @@ dependencies = [ "anyhow", "async-channel", "axum", - "base64 0.21.2", + "base64 0.21.3", "deltachat", "env_logger", "futures", @@ -2490,7 +2490,7 @@ checksum = "e4fb9858c8cd3dd924a5da5bc511363845a9bcfdfac066bb2ef8454eb6111546" dependencies = [ "abao", "anyhow", - "base64 0.21.2", + "base64 0.21.3", "blake3", "bytes", "default-net", @@ -3238,7 +3238,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27e1f8e085bfa9b85763fe3ddaacbe90a09cd847b3833129153a6cb063bbe132" dependencies = [ "aes", - "base64 0.21.2", + "base64 0.21.3", "bitfield", "block-padding", "blowfish", @@ -3834,7 +3834,7 @@ version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", "bytes", "encoding_rs", "futures-core", @@ -4055,7 +4055,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", ] [[package]] From cb0270baa7db7e283c1be7f055ce852b875732c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 21:07:19 +0000 Subject: [PATCH 065/102] chore(cargo): bump anyhow from 1.0.72 to 1.0.75 Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.72 to 1.0.75. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.72...1.0.75) --- updated-dependencies: - dependency-name: anyhow dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9efe2628b..a51465aa0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,9 +120,9 @@ checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" dependencies = [ "backtrace", ] From 2a39a85d9ea0c7fbfddff4e3884bb7100a95b04a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 21:08:47 +0000 Subject: [PATCH 066/102] chore(cargo): bump thiserror from 1.0.44 to 1.0.47 Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.44 to 1.0.47. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.44...1.0.47) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a51465aa0..c9901bb94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4714,18 +4714,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" dependencies = [ "proc-macro2", "quote", From aebad2eb10616a491a5ef90084c1fc24d6430159 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 21:08:13 +0000 Subject: [PATCH 067/102] chore(cargo): bump url from 2.4.0 to 2.4.1 Bumps [url](https://github.com/servo/rust-url) from 2.4.0 to 2.4.1. - [Release notes](https://github.com/servo/rust-url/releases) - [Commits](https://github.com/servo/rust-url/compare/v2.4.0...v2.4.1) --- updated-dependencies: - dependency-name: url dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9901bb94..e276de14f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5227,9 +5227,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna 0.4.0", From ab09ecce7eaaf03f057188978ac3fe70324bf3cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 21:09:07 +0000 Subject: [PATCH 068/102] chore(cargo): bump schemars from 0.8.12 to 0.8.13 Bumps [schemars](https://github.com/GREsau/schemars) from 0.8.12 to 0.8.13. - [Release notes](https://github.com/GREsau/schemars/releases) - [Changelog](https://github.com/GREsau/schemars/blob/master/CHANGELOG.md) - [Commits](https://github.com/GREsau/schemars/compare/v0.8.12...v0.8.13) --- updated-dependencies: - dependency-name: schemars dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 8 ++++---- deltachat-jsonrpc/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e276de14f..7143bf150 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4129,9 +4129,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.12" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" +checksum = "763f8cd0d4c71ed8389c90cb8100cba87e763bd01a8e614d4f0af97bcd50a161" dependencies = [ "dyn-clone", "schemars_derive", @@ -4141,9 +4141,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.12" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" +checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" dependencies = [ "proc-macro2", "quote", diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index f5812da18..08aa6fbb4 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -15,7 +15,7 @@ required-features = ["webserver"] anyhow = "1" deltachat = { path = ".." } num-traits = "0.2" -schemars = "0.8.11" +schemars = "0.8.13" serde = { version = "1.0", features = ["derive"] } tempfile = "3.6.0" log = "0.4" From 828c90ac3df85f5a4f4ac90bfdd90c23d05b89fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 21:06:14 +0000 Subject: [PATCH 069/102] chore(cargo): bump tokio from 1.29.1 to 1.32.0 Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.29.1 to 1.32.0. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.29.1...tokio-1.32.0) --- updated-dependencies: - dependency-name: tokio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 11 +++++------ deltachat-jsonrpc/Cargo.toml | 4 ++-- deltachat-rpc-server/Cargo.toml | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7143bf150..5c5cc9e26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3305,9 +3305,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -4808,11 +4808,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", @@ -4821,7 +4820,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.4.9", + "socket2 0.5.3", "tokio-macros", "windows-sys 0.48.0", ] diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index 08aa6fbb4..210550a68 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -24,7 +24,7 @@ futures = { version = "0.3.28" } serde_json = "1.0.99" yerpc = { version = "0.5.2", features = ["anyhow_expose", "openrpc"] } typescript-type-def = { version = "0.5.5", features = ["json_value"] } -tokio = { version = "1.29.1" } +tokio = { version = "1.32.0" } sanitize-filename = "0.5" walkdir = "2.3.3" base64 = "0.21" @@ -34,7 +34,7 @@ axum = { version = "0.6.18", optional = true, features = ["ws"] } env_logger = { version = "0.10.0", optional = true } [dev-dependencies] -tokio = { version = "1.29.1", features = ["full", "rt-multi-thread"] } +tokio = { version = "1.32.0", features = ["full", "rt-multi-thread"] } [features] diff --git a/deltachat-rpc-server/Cargo.toml b/deltachat-rpc-server/Cargo.toml index cf509dd2c..2d3bce6ab 100644 --- a/deltachat-rpc-server/Cargo.toml +++ b/deltachat-rpc-server/Cargo.toml @@ -19,7 +19,7 @@ futures-lite = "1.13.0" log = "0.4" serde_json = "1.0.99" serde = { version = "1.0", features = ["derive"] } -tokio = { version = "1.29.1", features = ["io-std"] } +tokio = { version = "1.32.0", features = ["io-std"] } tokio-util = "0.7.8" yerpc = { version = "0.5.2", features = ["anyhow_expose", "openrpc"] } From 486050d0b83875ffe9faf4abe0e364f76a948e80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Sep 2023 19:16:16 +0000 Subject: [PATCH 070/102] chore(cargo): bump backtrace from 0.3.68 to 0.3.69 Bumps [backtrace](https://github.com/rust-lang/backtrace-rs) from 0.3.68 to 0.3.69. - [Release notes](https://github.com/rust-lang/backtrace-rs/releases) - [Commits](https://github.com/rust-lang/backtrace-rs/compare/0.3.68...0.3.69) --- updated-dependencies: - dependency-name: backtrace dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5c5cc9e26..2f7332ccc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,9 +17,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -353,9 +353,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -2110,9 +2110,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "group" @@ -3006,9 +3006,9 @@ dependencies = [ [[package]] name = "object" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" dependencies = [ "memchr", ] From d9e38289c42329df1d6b6dbdc7452172c4e8b14a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 21:09:39 +0000 Subject: [PATCH 071/102] chore(cargo): bump image from 0.24.6 to 0.24.7 Bumps [image](https://github.com/image-rs/image) from 0.24.6 to 0.24.7. - [Changelog](https://github.com/image-rs/image/blob/master/CHANGES.md) - [Commits](https://github.com/image-rs/image/compare/v0.24.6...v0.24.7) --- updated-dependencies: - dependency-name: image dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5c5cc9e26..628963d49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2403,9 +2403,9 @@ dependencies = [ [[package]] name = "image" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" dependencies = [ "bytemuck", "byteorder", diff --git a/Cargo.toml b/Cargo.toml index 6b788c23f..c59c7919b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ futures = "0.3" futures-lite = "1.13.0" hex = "0.4.0" humansize = "2" -image = { version = "0.24.6", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] } +image = { version = "0.24.7", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] } iroh = { version = "0.4.1", default-features = false } kamadak-exif = "0.5" lettre_email = { git = "https://github.com/deltachat/lettre", branch = "master" } From e1f1143919eb6f93d50f232f8c237551eff4a2fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Sep 2023 18:27:47 +0000 Subject: [PATCH 072/102] chore(cargo): bump quote from 1.0.32 to 1.0.33 Bumps [quote](https://github.com/dtolnay/quote) from 1.0.32 to 1.0.33. - [Release notes](https://github.com/dtolnay/quote/releases) - [Commits](https://github.com/dtolnay/quote/compare/1.0.32...1.0.33) --- updated-dependencies: - dependency-name: quote dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 628963d49..1ea91f72a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3614,9 +3614,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] From 8ac1754e18d320666dcaf44d55a7ad36fd413b5a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Sep 2023 18:27:37 +0000 Subject: [PATCH 073/102] chore(cargo): bump tempfile from 3.7.0 to 3.8.0 Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.7.0 to 3.8.0. - [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md) - [Commits](https://github.com/Stebalien/tempfile/compare/v3.7.0...v3.8.0) --- updated-dependencies: - dependency-name: tempfile dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- deltachat-jsonrpc/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ea91f72a..5f6c75bd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4667,9 +4667,9 @@ checksum = "094c9f64d6de9a8506b1e49b63a29333b37ed9e821ee04be694d431b3264c3c5" [[package]] name = "tempfile" -version = "3.7.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if", "fastrand 2.0.0", diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index 210550a68..4e9554e33 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -17,7 +17,7 @@ deltachat = { path = ".." } num-traits = "0.2" schemars = "0.8.13" serde = { version = "1.0", features = ["derive"] } -tempfile = "3.6.0" +tempfile = "3.8.0" log = "0.4" async-channel = { version = "1.8.0" } futures = { version = "0.3.28" } From d8bf1c16918ea633d2668ccaef038039a526f59e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 21:07:55 +0000 Subject: [PATCH 074/102] chore(cargo): bump reqwest from 0.11.18 to 0.11.20 Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.11.18 to 0.11.20. - [Release notes](https://github.com/seanmonstar/reqwest/releases) - [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md) - [Commits](https://github.com/seanmonstar/reqwest/compare/v0.11.18...v0.11.20) --- updated-dependencies: - dependency-name: reqwest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 17 ++++------------- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f6c75bd3..5e552d542 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2473,7 +2473,7 @@ dependencies = [ "socket2 0.5.3", "widestring", "windows-sys 0.48.0", - "winreg 0.50.0", + "winreg", ] [[package]] @@ -3830,9 +3830,9 @@ checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ "base64 0.21.3", "bytes", @@ -3862,7 +3862,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg 0.10.1", + "winreg", ] [[package]] @@ -5650,15 +5650,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - [[package]] name = "winreg" version = "0.50.0" diff --git a/Cargo.toml b/Cargo.toml index c59c7919b..00732497e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,7 +72,7 @@ qrcodegen = "1.7.0" quick-xml = "0.30" rand = "0.8" regex = "1.8" -reqwest = { version = "0.11.18", features = ["json"] } +reqwest = { version = "0.11.20", features = ["json"] } rusqlite = { version = "0.29", features = ["sqlcipher"] } rust-hsluv = "0.1" sanitize-filename = "0.5" From ec56134583c69057bd3f07e115d2940680484d05 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 2 Sep 2023 18:40:09 +0000 Subject: [PATCH 075/102] Remove `winreg` entry from deny.toml --- deny.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/deny.toml b/deny.toml index 643aae78e..62798c94d 100644 --- a/deny.toml +++ b/deny.toml @@ -62,7 +62,6 @@ skip = [ { name = "windows_x86_64_gnullvm", version = "<0.48" }, { name = "windows_x86_64_gnu", version = "<0.48" }, { name = "windows_x86_64_msvc", version = "<0.48" }, - { name = "winreg", version = "0.10.1" }, ] From 0a4c993bb8c9284f0cce4e37ddc8d77c22e054f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Sep 2023 19:16:39 +0000 Subject: [PATCH 076/102] chore(cargo): bump serde_json from 1.0.104 to 1.0.105 Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.104 to 1.0.105. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.104...v1.0.105) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- deltachat-jsonrpc/Cargo.toml | 2 +- deltachat-rpc-server/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e552d542..86cc0c300 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4284,9 +4284,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" dependencies = [ "itoa", "ryu", diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index 4e9554e33..1be67da05 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -21,7 +21,7 @@ tempfile = "3.8.0" log = "0.4" async-channel = { version = "1.8.0" } futures = { version = "0.3.28" } -serde_json = "1.0.99" +serde_json = "1.0.105" yerpc = { version = "0.5.2", features = ["anyhow_expose", "openrpc"] } typescript-type-def = { version = "0.5.5", features = ["json_value"] } tokio = { version = "1.32.0" } diff --git a/deltachat-rpc-server/Cargo.toml b/deltachat-rpc-server/Cargo.toml index 2d3bce6ab..ec28043d5 100644 --- a/deltachat-rpc-server/Cargo.toml +++ b/deltachat-rpc-server/Cargo.toml @@ -17,7 +17,7 @@ anyhow = "1" env_logger = { version = "0.10.0" } futures-lite = "1.13.0" log = "0.4" -serde_json = "1.0.99" +serde_json = "1.0.105" serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.32.0", features = ["io-std"] } tokio-util = "0.7.8" From 72c94e1037b5a96fc1b22ebb89ca8d8e0fda1b42 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 3 Sep 2023 00:03:50 +0000 Subject: [PATCH 077/102] chore(cargo): bump serde from 1.0.180 to 1.0.188 Bumps [serde](https://github.com/serde-rs/serde) from 1.0.180 to 1.0.188. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.180...v1.0.188) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 86cc0c300..3c0621c47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4235,9 +4235,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.180" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] @@ -4262,9 +4262,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.180" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", From 1b883ae3fa09fe062935f14e751eea5216b0424c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 3 Sep 2023 00:03:55 +0000 Subject: [PATCH 078/102] chore(cargo): bump typescript-type-def from 0.5.7 to 0.5.8 Bumps [typescript-type-def](https://github.com/dbeckwith/rust-typescript-type-def) from 0.5.7 to 0.5.8. - [Changelog](https://github.com/dbeckwith/rust-typescript-type-def/blob/master/CHANGELOG.md) - [Commits](https://github.com/dbeckwith/rust-typescript-type-def/compare/v0.5.7...v0.5.8) --- updated-dependencies: - dependency-name: typescript-type-def dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 8 ++++---- deltachat-jsonrpc/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3c0621c47..a9164553e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5145,9 +5145,9 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "typescript-type-def" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c4be05eb0171e18da471e545cfff85d80b8118e5aa2d50c2d152265d7435997" +checksum = "356e00027bd9ef773605a353070dc87684b25561a59087ea3ee3dd5fe8854e83" dependencies = [ "serde_json", "typescript-type-def-derive", @@ -5155,9 +5155,9 @@ dependencies = [ [[package]] name = "typescript-type-def-derive" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71aeb2295da6c2bfe665493332b4e4281d113fab3a0786e9651dcc85708095a4" +checksum = "c4e696c28431595138cc53892104528152cbcf26653ae0aa655e4eaede5b9f69" dependencies = [ "darling 0.13.4", "ident_case", diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index 1be67da05..08eb056c7 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -23,7 +23,7 @@ async-channel = { version = "1.8.0" } futures = { version = "0.3.28" } serde_json = "1.0.105" yerpc = { version = "0.5.2", features = ["anyhow_expose", "openrpc"] } -typescript-type-def = { version = "0.5.5", features = ["json_value"] } +typescript-type-def = { version = "0.5.8", features = ["json_value"] } tokio = { version = "1.32.0" } sanitize-filename = "0.5" walkdir = "2.3.3" From b36acb2dc0ba6aa878e1854afdff3e4d4196d1da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 3 Sep 2023 00:03:10 +0000 Subject: [PATCH 079/102] chore(cargo): bump log from 0.4.19 to 0.4.20 Bumps [log](https://github.com/rust-lang/log) from 0.4.19 to 0.4.20. - [Release notes](https://github.com/rust-lang/log/releases) - [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/log/compare/0.4.19...0.4.20) --- updated-dependencies: - dependency-name: log dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- deltachat-repl/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9164553e..27d305a63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2666,9 +2666,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "lru-cache" diff --git a/deltachat-repl/Cargo.toml b/deltachat-repl/Cargo.toml index 32402d1d0..1278938f5 100644 --- a/deltachat-repl/Cargo.toml +++ b/deltachat-repl/Cargo.toml @@ -9,7 +9,7 @@ ansi_term = "0.12.1" anyhow = "1" deltachat = { path = "..", features = ["internals"]} dirs = "5" -log = "0.4.19" +log = "0.4.20" pretty_env_logger = "0.5" rusqlite = "0.29" rustyline = "12" From 54d632adafc37fabf791619ddf5dc6cc0d7b68bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Sep 2023 19:16:13 +0000 Subject: [PATCH 080/102] chore(cargo): bump axum from 0.6.19 to 0.6.20 Bumps [axum](https://github.com/tokio-rs/axum) from 0.6.19 to 0.6.20. - [Release notes](https://github.com/tokio-rs/axum/releases) - [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/axum/compare/axum-v0.6.19...axum-v0.6.20) --- updated-dependencies: - dependency-name: axum dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 12 ++++++------ deltachat-jsonrpc/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 89e65cfdc..16f669516 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -301,9 +301,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.19" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a1de45611fdb535bfde7b7de4fd54f4fd2b17b1737c0a59b69bf9b92074b8c" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", "axum-core", @@ -4899,9 +4899,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec509ac96e9a0c43427c74f003127d953a265737636129424288d27cb5c4b12c" +checksum = "2b2dbec703c26b00d74844519606ef15d09a7d6857860f84ad223dec002ddea2" dependencies = [ "futures-util", "log", @@ -5111,9 +5111,9 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "tungstenite" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15fba1a6d6bb030745759a9a2a588bfe8490fc8b4751a277db3a0be1c9ebbf67" +checksum = "e862a1c4128df0112ab625f55cd5c934bcb4312ba80b39ae4b4835a3fd58e649" dependencies = [ "byteorder", "bytes", diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index 08eb056c7..cb8298ad0 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -30,7 +30,7 @@ walkdir = "2.3.3" base64 = "0.21" # optional dependencies -axum = { version = "0.6.18", optional = true, features = ["ws"] } +axum = { version = "0.6.20", optional = true, features = ["ws"] } env_logger = { version = "0.10.0", optional = true } [dev-dependencies] From 178fc1736d2d65d41442fc7226bf75780c097bd1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 21:10:15 +0000 Subject: [PATCH 081/102] chore(cargo): bump trust-dns-resolver from 0.22.0 to 0.23.0 Bumps [trust-dns-resolver](https://github.com/bluejekyll/trust-dns) from 0.22.0 to 0.23.0. - [Release notes](https://github.com/bluejekyll/trust-dns/releases) - [Changelog](https://github.com/bluejekyll/trust-dns/blob/main/CHANGELOG.md) - [Commits](https://github.com/bluejekyll/trust-dns/compare/v0.22.0...v0.23.0) --- updated-dependencies: - dependency-name: trust-dns-resolver dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 40 ++++++++++++---------------------------- Cargo.toml | 2 +- 2 files changed, 13 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16f669516..907e7def6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1707,14 +1707,14 @@ checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" [[package]] name = "enum-as-inner" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" +checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" dependencies = [ "heck", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] @@ -2380,17 +2380,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.4.0" @@ -2705,12 +2694,6 @@ dependencies = [ "regex-automata 0.1.10", ] -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "matchit" version = "0.7.1" @@ -5060,9 +5043,9 @@ dependencies = [ [[package]] name = "trust-dns-proto" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" +checksum = "0dc775440033cb114085f6f2437682b194fa7546466024b1037e82a48a052a69" dependencies = [ "async-trait", "cfg-if", @@ -5071,9 +5054,9 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna 0.2.3", + "idna", "ipnet", - "lazy_static", + "once_cell", "rand 0.8.5", "smallvec", "thiserror", @@ -5085,16 +5068,17 @@ dependencies = [ [[package]] name = "trust-dns-resolver" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" +checksum = "2dff7aed33ef3e8bf2c9966fccdfed93f93d46f432282ea875cd66faabc6ef2f" dependencies = [ "cfg-if", "futures-util", "ipconfig", - "lazy_static", "lru-cache", + "once_cell", "parking_lot", + "rand 0.8.5", "resolv-conf", "smallvec", "thiserror", @@ -5231,7 +5215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", - "idna 0.4.0", + "idna", "percent-encoding", ] diff --git a/Cargo.toml b/Cargo.toml index 00732497e..7edc410c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,7 +92,7 @@ tokio-stream = { version = "0.1.14", features = ["fs"] } tokio-tar = { version = "0.3" } # TODO: integrate tokio into async-tar tokio-util = "0.7.8" toml = "0.7" -trust-dns-resolver = "0.22" +trust-dns-resolver = "0.23" url = "2" uuid = { version = "1", features = ["serde", "v4"] } From e9811fb6da5409eceefc829fba026388aea85bfa Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 2 Sep 2023 22:13:07 +0000 Subject: [PATCH 082/102] AsyncResolver::tokio does not return a Result anymore --- src/provider.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/provider.rs b/src/provider.rs index 1df329c1d..e27f9d631 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -171,7 +171,7 @@ fn get_resolver() -> Result { let resolver = AsyncResolver::tokio( config::ResolverConfig::default(), config::ResolverOpts::default(), - )?; + ); Ok(resolver) } From f94d34c94b5f00aaf3c3571065d3bcf5a4c2021a Mon Sep 17 00:00:00 2001 From: link2xt Date: Sun, 3 Sep 2023 00:02:44 +0000 Subject: [PATCH 083/102] chore: remove idna from deny.toml --- deny.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/deny.toml b/deny.toml index 62798c94d..8c5fb1dd5 100644 --- a/deny.toml +++ b/deny.toml @@ -32,7 +32,6 @@ skip = [ { name = "fastrand", version = "1.9.0" }, { name = "getrandom", version = "<0.2" }, { name = "hashbrown", version = "<0.14.0" }, - { name = "idna", version = "<0.3" }, { name = "indexmap", version = "<2.0.0" }, { name = "pem-rfc7468", version = "0.6.0" }, { name = "pkcs8", version = "0.9.0" }, From f05b0ddf046155471dc33b9ed1db6e6cd625c11d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 19:09:31 +0000 Subject: [PATCH 084/102] chore(cargo): bump regex from 1.9.1 to 1.9.5 Bumps [regex](https://github.com/rust-lang/regex) from 1.9.1 to 1.9.5. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.9.1...1.9.5) --- updated-dependencies: - dependency-name: regex dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 24 ++++++++++++------------ Cargo.toml | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 907e7def6..895f67f89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1714,7 +1714,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -2717,9 +2717,9 @@ checksum = "df39d232f5c40b0891c10216992c2f250c054105cb1e56f0fc9032db6203ecc1" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "memoffset" @@ -3769,14 +3769,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.4", - "regex-syntax 0.7.4", + "regex-automata 0.3.8", + "regex-syntax 0.7.5", ] [[package]] @@ -3790,13 +3790,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.4" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.7.5", ] [[package]] @@ -3807,9 +3807,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "reqwest" diff --git a/Cargo.toml b/Cargo.toml index 7edc410c2..09094a650 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ pretty_env_logger = { version = "0.5", optional = true } qrcodegen = "1.7.0" quick-xml = "0.30" rand = "0.8" -regex = "1.8" +regex = "1.9" reqwest = { version = "0.11.20", features = ["json"] } rusqlite = { version = "0.29", features = ["sqlcipher"] } rust-hsluv = "0.1" From 2587ebbacdf1e5252f0de05473de2ecc020e2ed5 Mon Sep 17 00:00:00 2001 From: Hocuri Date: Tue, 5 Sep 2023 09:15:15 +0200 Subject: [PATCH 085/102] fix: Clear VerifiedOneOnOneChats config on backup (#4681) If the user makes a backup from a UI that supports the experimental verified 1:1 chats (e.g. nightly Android) and imports it into a UI that doesn't, then this config should be cleared. We already talked about this a long time ago after @Simon-Laux noticed this problem, but I think we didn't actually solve it back then? Best to review with whitespace changes disabled. --- src/imex.rs | 107 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 42 deletions(-) diff --git a/src/imex.rs b/src/imex.rs index 94c9c97a5..7f2ce009e 100644 --- a/src/imex.rs +++ b/src/imex.rs @@ -771,6 +771,11 @@ async fn export_database(context: &Context, dest: &Path, passphrase: String) -> let res = conn .query_row("SELECT sqlcipher_export('backup')", [], |_row| Ok(())) .context("failed to export to attached backup database"); + conn.execute( + "UPDATE backup.config SET value='0' WHERE keyname='verified_one_on_one_chats';", + [], + ) + .ok(); // If verified_one_on_one_chats was not set, this errors, which we ignore conn.execute("DETACH DATABASE backup", []) .context("failed to detach backup database")?; res?; @@ -880,55 +885,73 @@ mod tests { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_export_and_import_backup() -> Result<()> { - let backup_dir = tempfile::tempdir().unwrap(); + for set_verified_oneonone_chats in [true, false] { + let backup_dir = tempfile::tempdir().unwrap(); - let context1 = TestContext::new_alice().await; - assert!(context1.is_configured().await?); + let context1 = TestContext::new_alice().await; + assert!(context1.is_configured().await?); + if set_verified_oneonone_chats { + context1 + .set_config_bool(Config::VerifiedOneOnOneChats, true) + .await?; + } - let context2 = TestContext::new().await; - assert!(!context2.is_configured().await?); - assert!(has_backup(&context2, backup_dir.path()).await.is_err()); + let context2 = TestContext::new().await; + assert!(!context2.is_configured().await?); + assert!(has_backup(&context2, backup_dir.path()).await.is_err()); - // export from context1 - assert!( - imex(&context1, ImexMode::ExportBackup, backup_dir.path(), None) - .await - .is_ok() - ); - let _event = context1 - .evtracker - .get_matching(|evt| matches!(evt, EventType::ImexProgress(1000))) - .await; + // export from context1 + assert!( + imex(&context1, ImexMode::ExportBackup, backup_dir.path(), None) + .await + .is_ok() + ); + let _event = context1 + .evtracker + .get_matching(|evt| matches!(evt, EventType::ImexProgress(1000))) + .await; - // import to context2 - let backup = has_backup(&context2, backup_dir.path()).await?; + // import to context2 + let backup = has_backup(&context2, backup_dir.path()).await?; - // Import of unencrypted backup with incorrect "foobar" backup passphrase fails. - assert!(imex( - &context2, - ImexMode::ImportBackup, - backup.as_ref(), - Some("foobar".to_string()) - ) - .await - .is_err()); + // Import of unencrypted backup with incorrect "foobar" backup passphrase fails. + assert!(imex( + &context2, + ImexMode::ImportBackup, + backup.as_ref(), + Some("foobar".to_string()) + ) + .await + .is_err()); - assert!( - imex(&context2, ImexMode::ImportBackup, backup.as_ref(), None) - .await - .is_ok() - ); - let _event = context2 - .evtracker - .get_matching(|evt| matches!(evt, EventType::ImexProgress(1000))) - .await; - - assert!(context2.is_configured().await?); - assert_eq!( - context2.get_config(Config::Addr).await?, - Some("alice@example.org".to_string()) - ); + assert!( + imex(&context2, ImexMode::ImportBackup, backup.as_ref(), None) + .await + .is_ok() + ); + let _event = context2 + .evtracker + .get_matching(|evt| matches!(evt, EventType::ImexProgress(1000))) + .await; + assert!(context2.is_configured().await?); + assert_eq!( + context2.get_config(Config::Addr).await?, + Some("alice@example.org".to_string()) + ); + assert_eq!( + context2 + .get_config_bool(Config::VerifiedOneOnOneChats) + .await?, + false + ); + assert_eq!( + context1 + .get_config_bool(Config::VerifiedOneOnOneChats) + .await?, + set_verified_oneonone_chats + ); + } Ok(()) } From 4a0585404a0a5f2e3edb4257a69d63efeb199ef3 Mon Sep 17 00:00:00 2001 From: link2xt Date: Fri, 8 Sep 2023 07:00:18 +0000 Subject: [PATCH 086/102] chore(cargo): bump webpki from 0.22.0 to 0.22.1 --- Cargo.lock | 4 ++-- deny.toml | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b73af324..e2008e24f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5380,9 +5380,9 @@ dependencies = [ [[package]] name = "webpki" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +checksum = "f0e74f82d49d545ad128049b7e88f6576df2da6b02e9ce565c6f533be576957e" dependencies = [ "ring", "untrusted", diff --git a/deny.toml b/deny.toml index 8c5fb1dd5..22d06bab4 100644 --- a/deny.toml +++ b/deny.toml @@ -3,11 +3,6 @@ unmaintained = "allow" ignore = [ "RUSTSEC-2020-0071", "RUSTSEC-2022-0093", - - # Exponential CPU time usage for TLS certificate processing in webpki. - # It is only used for backup transfer, so does not affect IMAP and SMTP connections. - # Waiting for `iroh` to update dependencies. - "RUSTSEC-2023-0052", ] [bans] From e7617f0abd0ebd15c48960b9d5ea210698a57f3f Mon Sep 17 00:00:00 2001 From: link2xt Date: Tue, 12 Sep 2023 19:02:14 +0000 Subject: [PATCH 087/102] build(coredeps): install perl-IPC-Cmd It is required to configure OpenSSL 3.0. --- scripts/coredeps/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/coredeps/Dockerfile b/scripts/coredeps/Dockerfile index a6ceed532..62bda3040 100644 --- a/scripts/coredeps/Dockerfile +++ b/scripts/coredeps/Dockerfile @@ -6,3 +6,4 @@ FROM $BASEIMAGE RUN pipx install tox COPY install-rust.sh /scripts/ RUN /scripts/install-rust.sh +RUN yum install -y perl-IPC-Cmd From 061d091c971ac8cb860f92e6e81c298dcffa8f26 Mon Sep 17 00:00:00 2001 From: link2xt Date: Tue, 12 Sep 2023 19:59:15 +0000 Subject: [PATCH 088/102] build(coredeps): only run `yum` if it is available musllinux is based on Alpine and has no yum --- scripts/coredeps/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/coredeps/Dockerfile b/scripts/coredeps/Dockerfile index 62bda3040..55b90d9f6 100644 --- a/scripts/coredeps/Dockerfile +++ b/scripts/coredeps/Dockerfile @@ -6,4 +6,4 @@ FROM $BASEIMAGE RUN pipx install tox COPY install-rust.sh /scripts/ RUN /scripts/install-rust.sh -RUN yum install -y perl-IPC-Cmd +RUN if command -v yum; then yum install -y perl-IPC-Cmd; fi From a42a6ca18c2106ecc9cb625a8538b4404d2f4eed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:26:12 +0000 Subject: [PATCH 089/102] chore(deps): bump quinn-proto from 0.9.2 to 0.9.5 in /fuzz Bumps [quinn-proto](https://github.com/quinn-rs/quinn) from 0.9.2 to 0.9.5. - [Release notes](https://github.com/quinn-rs/quinn/releases) - [Commits](https://github.com/quinn-rs/quinn/commits) --- updated-dependencies: - dependency-name: quinn-proto dependency-type: indirect ... Signed-off-by: dependabot[bot] --- fuzz/Cargo.lock | 320 +++++++++++++++++++++++++++++++----------------- 1 file changed, 208 insertions(+), 112 deletions(-) diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 097b7ac9b..89a93781c 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -177,13 +177,13 @@ dependencies = [ [[package]] name = "async-imap" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da93622739d458dd9a6abc1abf0e38e81965a5824a3b37f9500437c82a8bb572" +checksum = "b538b767cbf9c162a6c5795d4b932bd2c20ba10b5a91a94d2b2b6886c1dce6a8" dependencies = [ "async-channel", "base64 0.21.0", - "byte-pool", + "bytes", "chrono", "futures", "imap-proto", @@ -337,9 +337,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.0.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487f1e0fcbe47deb8b0574e646def1c903389d95241dd1bbcc6ce4a715dfc0c1" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "blake3" @@ -529,16 +529,6 @@ version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" -[[package]] -name = "byte-pool" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f1b21189f50b5625efa6227cf45e9d4cfdc2e73582df2b879e9689e78a7158" -dependencies = [ - "crossbeam-queue", - "stable_deref_trait", -] - [[package]] name = "bytemuck" version = "1.12.3" @@ -741,16 +731,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-queue" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.14" @@ -926,7 +906,7 @@ dependencies = [ [[package]] name = "deltachat" -version = "1.117.0" +version = "1.122.0" dependencies = [ "anyhow", "async-channel", @@ -943,6 +923,7 @@ dependencies = [ "encoded-words", "escaper", "fast-socks5", + "fd-lock", "format-flowed", "futures", "futures-lite", @@ -955,7 +936,7 @@ dependencies = [ "libc", "mailparse 0.14.0", "mime", - "num-derive", + "num-derive 0.4.0", "num-traits", "num_cpus", "once_cell", @@ -1429,14 +1410,14 @@ checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" [[package]] name = "enum-as-inner" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" +checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" dependencies = [ "heck", "proc-macro2", "quote", - "syn 1.0.107", + "syn 2.0.15", ] [[package]] @@ -1464,6 +1445,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "errno" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "errno-dragonfly" version = "0.1.2" @@ -1532,6 +1524,17 @@ dependencies = [ "instant", ] +[[package]] +name = "fd-lock" +version = "3.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" +dependencies = [ + "cfg-if", + "rustix 0.38.14", + "windows-sys 0.48.0", +] + [[package]] name = "ff" version = "0.12.1" @@ -1616,9 +1619,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -1843,18 +1846,15 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hex" @@ -2012,20 +2012,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.2.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -2033,9 +2022,9 @@ dependencies = [ [[package]] name = "image" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" dependencies = [ "bytemuck", "byteorder", @@ -2103,7 +2092,7 @@ dependencies = [ "socket2", "widestring", "winapi", - "winreg", + "winreg 0.10.1", ] [[package]] @@ -2230,9 +2219,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.139" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libm" @@ -2279,6 +2268,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +[[package]] +name = "linux-raw-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" + [[package]] name = "lock_api" version = "0.4.9" @@ -2341,15 +2336,9 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - [[package]] name = "md-5" version = "0.10.5" @@ -2367,9 +2356,9 @@ checksum = "df39d232f5c40b0891c10216992c2f250c054105cb1e56f0fc9032db6203ecc1" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "mime" @@ -2555,6 +2544,17 @@ dependencies = [ "syn 1.0.107", ] +[[package]] +name = "num-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -2599,9 +2599,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", @@ -2854,7 +2854,7 @@ dependencies = [ "md-5", "nom", "num-bigint-dig", - "num-derive", + "num-derive 0.3.3", "num-traits", "p256 0.13.1", "p384 0.13.0", @@ -3087,9 +3087,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quick-xml" -version = "0.28.2" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" dependencies = [ "memchr", ] @@ -3114,9 +3114,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.9.2" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4ced82a24bb281af338b9e8f94429b6eca01b4e66d899f40031f074e74c9" +checksum = "c956be1b23f4261676aed05a0046e204e8a6836e50203902683a718af0797989" dependencies = [ "bytes", "rand 0.8.5", @@ -3268,13 +3268,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.2", + "regex-automata 0.3.8", + "regex-syntax 0.7.5", ] [[package]] @@ -3286,6 +3287,17 @@ dependencies = [ "regex-syntax 0.6.28", ] +[[package]] +name = "regex-automata" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.5", +] + [[package]] name = "regex-syntax" version = "0.6.28" @@ -3294,15 +3306,15 @@ checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ "base64 0.21.0", "bytes", @@ -3332,7 +3344,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg", + "winreg 0.50.0", ] [[package]] @@ -3438,7 +3450,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" dependencies = [ - "bitflags 2.0.2", + "bitflags 2.4.0", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -3489,13 +3501,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" dependencies = [ "bitflags 1.3.2", - "errno", + "errno 0.2.8", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.1.4", "windows-sys 0.42.0", ] +[[package]] +name = "rustix" +version = "0.38.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" +dependencies = [ + "bitflags 2.4.0", + "errno 0.3.3", + "libc", + "linux-raw-sys 0.4.7", + "windows-sys 0.48.0", +] + [[package]] name = "rustls" version = "0.20.8" @@ -3557,9 +3582,9 @@ dependencies = [ [[package]] name = "sanitize-filename" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c502bdb638f1396509467cb0580ef3b29aa2a45c5d43e5d84928241280296c" +checksum = "2ed72fbaf78e6f2d41744923916966c4fbe3d7c74e3037a8ee482f1115572603" dependencies = [ "lazy_static", "regex", @@ -3919,12 +3944,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "stop-token" version = "0.7.0" @@ -3945,21 +3964,21 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.24.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" [[package]] name = "strum_macros" -version = "0.24.3" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" dependencies = [ "heck", "proc-macro2", "quote", "rustversion", - "syn 1.0.107", + "syn 2.0.15", ] [[package]] @@ -4038,7 +4057,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall", - "rustix", + "rustix 0.36.7", "windows-sys 0.42.0", ] @@ -4365,9 +4384,9 @@ dependencies = [ [[package]] name = "trust-dns-proto" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" +checksum = "0dc775440033cb114085f6f2437682b194fa7546466024b1037e82a48a052a69" dependencies = [ "async-trait", "cfg-if", @@ -4376,9 +4395,9 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna 0.2.3", + "idna", "ipnet", - "lazy_static", + "once_cell", "rand 0.8.5", "smallvec", "thiserror", @@ -4390,16 +4409,17 @@ dependencies = [ [[package]] name = "trust-dns-resolver" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" +checksum = "2dff7aed33ef3e8bf2c9966fccdfed93f93d46f432282ea875cd66faabc6ef2f" dependencies = [ "cfg-if", "futures-util", "ipconfig", - "lazy_static", "lru-cache", + "once_cell", "parking_lot", + "rand 0.8.5", "resolv-conf", "smallvec", "thiserror", @@ -4431,9 +4451,9 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" @@ -4480,12 +4500,12 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.3.1" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", - "idna 0.3.0", + "idna", "percent-encoding", ] @@ -4731,21 +4751,51 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", + "windows_aarch64_gnullvm 0.42.0", "windows_aarch64_msvc 0.42.0", "windows_i686_gnu 0.42.0", "windows_i686_msvc 0.42.0", "windows_x86_64_gnu 0.42.0", - "windows_x86_64_gnullvm", + "windows_x86_64_gnullvm 0.42.0", "windows_x86_64_msvc 0.42.0", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_msvc" version = "0.32.0" @@ -4764,6 +4814,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_i686_gnu" version = "0.32.0" @@ -4782,6 +4838,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_msvc" version = "0.32.0" @@ -4800,6 +4862,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_x86_64_gnu" version = "0.32.0" @@ -4818,12 +4886,24 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_msvc" version = "0.32.0" @@ -4842,6 +4922,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "winreg" version = "0.10.1" @@ -4851,6 +4937,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "x25519-dalek" version = "2.0.0-pre.1" From d109a1b27f516bf123892c03599999556befdccc Mon Sep 17 00:00:00 2001 From: Hocuri Date: Fri, 29 Sep 2023 17:06:26 +0200 Subject: [PATCH 090/102] Fix link to the template documentation of git-cliff The old link gives me 404 --- cliff.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cliff.toml b/cliff.toml index 86a2303e5..98a959c28 100644 --- a/cliff.toml +++ b/cliff.toml @@ -54,7 +54,7 @@ header = """ # Changelog\n """ # template for the changelog body -# https://tera.netlify.app/docs/#introduction +# https://keats.github.io/tera/docs/#templates body = """ {% if version %}\ ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} From e500485c2190fd244de12d0a8a97128bcfd262f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 21:42:27 +0000 Subject: [PATCH 091/102] chore(cargo): bump brotli from 3.3.4 to 3.4.0 Bumps [brotli](https://github.com/dropbox/rust-brotli) from 3.3.4 to 3.4.0. - [Release notes](https://github.com/dropbox/rust-brotli/releases) - [Commits](https://github.com/dropbox/rust-brotli/commits) --- updated-dependencies: - dependency-name: brotli dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e18940f5..16ae466e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -488,9 +488,9 @@ dependencies = [ [[package]] name = "brotli" -version = "3.3.4" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -499,9 +499,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.3.4" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" +checksum = "da74e2b81409b1b743f8f0c62cc6254afefb8b8e50bbfe3735550f7aeefa3448" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", diff --git a/Cargo.toml b/Cargo.toml index 229451cf5..9102edb16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ async-smtp = { version = "0.9", default-features = false, features = ["runtime-t async_zip = { version = "0.0.12", default-features = false, features = ["deflate", "fs"] } backtrace = "0.3" base64 = "0.21" -brotli = { version = "3.3", default-features=false, features = ["std"] } +brotli = { version = "3.4", default-features=false, features = ["std"] } chrono = { version = "0.4", default-features=false, features = ["clock", "std"] } email = { git = "https://github.com/deltachat/rust-email", branch = "master" } encoded-words = { git = "https://github.com/async-email/encoded-words", branch = "master" } From 3166b4458040208446edf942cbf4d222d1afafaf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 21:42:54 +0000 Subject: [PATCH 092/102] chore(cargo): bump tokio-util from 0.7.8 to 0.7.9 Bumps [tokio-util](https://github.com/tokio-rs/tokio) from 0.7.8 to 0.7.9. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-util-0.7.8...tokio-util-0.7.9) --- updated-dependencies: - dependency-name: tokio-util dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- deltachat-rpc-server/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e18940f5..e818c6b12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4894,9 +4894,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" dependencies = [ "bytes", "futures-core", diff --git a/Cargo.toml b/Cargo.toml index 229451cf5..60eded7ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,7 +90,7 @@ tokio = { version = "1", features = ["fs", "rt-multi-thread", "macros"] } tokio-io-timeout = "1.2.0" tokio-stream = { version = "0.1.14", features = ["fs"] } tokio-tar = { version = "0.3" } # TODO: integrate tokio into async-tar -tokio-util = "0.7.8" +tokio-util = "0.7.9" toml = "0.7" trust-dns-resolver = "0.23" url = "2" diff --git a/deltachat-rpc-server/Cargo.toml b/deltachat-rpc-server/Cargo.toml index 13cdf7ce7..994d5e963 100644 --- a/deltachat-rpc-server/Cargo.toml +++ b/deltachat-rpc-server/Cargo.toml @@ -20,7 +20,7 @@ log = "0.4" serde_json = "1.0.105" serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.32.0", features = ["io-std"] } -tokio-util = "0.7.8" +tokio-util = "0.7.9" yerpc = { version = "0.5.2", features = ["anyhow_expose", "openrpc"] } [features] From 6b2df13cdb3f6e111c14308fac60d0b513a6b107 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 21:43:13 +0000 Subject: [PATCH 093/102] chore(cargo): bump thiserror from 1.0.47 to 1.0.49 Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.47 to 1.0.49. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.47...1.0.49) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e18940f5..151b71f1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4697,18 +4697,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.47" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.47" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", From 573746ce546828d0f2824839dbced00a57330ff0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 21:43:32 +0000 Subject: [PATCH 094/102] chore(cargo): bump regex from 1.9.5 to 1.9.6 Bumps [regex](https://github.com/rust-lang/regex) from 1.9.5 to 1.9.6. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.9.5...1.9.6) --- updated-dependencies: - dependency-name: regex dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e18940f5..badc39069 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3769,13 +3769,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.5" +version = "1.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.8", + "regex-automata 0.3.9", "regex-syntax 0.7.5", ] @@ -3790,9 +3790,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" dependencies = [ "aho-corasick", "memchr", From e4e50d0e8161805ba59bb28270188e9fe24e2e9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 21:43:50 +0000 Subject: [PATCH 095/102] chore(cargo): bump smallvec from 1.11.0 to 1.11.1 Bumps [smallvec](https://github.com/servo/rust-smallvec) from 1.11.0 to 1.11.1. - [Release notes](https://github.com/servo/rust-smallvec/releases) - [Commits](https://github.com/servo/rust-smallvec/compare/v1.11.0...v1.11.1) --- updated-dependencies: - dependency-name: smallvec dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e18940f5..0beab4645 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4418,9 +4418,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "smawk" From c0195ab23f71976a87a97abc21307021a92cdd6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 21:44:09 +0000 Subject: [PATCH 096/102] chore(cargo): bump sha2 from 0.10.7 to 0.10.8 Bumps [sha2](https://github.com/RustCrypto/hashes) from 0.10.7 to 0.10.8. - [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.10.7...sha2-v0.10.8) --- updated-dependencies: - dependency-name: sha2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e18940f5..68eecf956 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1140,7 +1140,7 @@ dependencies = [ "serde", "serde_json", "sha-1", - "sha2 0.10.7", + "sha2 0.10.8", "smallvec", "strum", "strum_macros", @@ -1529,7 +1529,7 @@ dependencies = [ "curve25519-dalek 4.0.0-rc.3", "ed25519 2.2.1", "serde", - "sha2 0.10.7", + "sha2 0.10.8", "zeroize", ] @@ -3108,7 +3108,7 @@ checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" dependencies = [ "ecdsa 0.14.8", "elliptic-curve 0.12.3", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -3120,7 +3120,7 @@ dependencies = [ "ecdsa 0.16.8", "elliptic-curve 0.13.5", "primeorder", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -3131,7 +3131,7 @@ checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa" dependencies = [ "ecdsa 0.14.8", "elliptic-curve 0.12.3", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -3143,7 +3143,7 @@ dependencies = [ "ecdsa 0.16.8", "elliptic-curve 0.13.5", "primeorder", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -3256,7 +3256,7 @@ dependencies = [ "ripemd", "rsa 0.9.2", "sha1", - "sha2 0.10.7", + "sha2 0.10.8", "sha3", "signature 2.1.0", "smallvec", @@ -4344,9 +4344,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -4491,7 +4491,7 @@ checksum = "19cfdc32e0199062113edf41f344fbf784b8205a94600233c84eb838f45191e1" dependencies = [ "base64ct", "pem-rfc7468 0.6.0", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -4506,7 +4506,7 @@ dependencies = [ "rand_core 0.6.4", "rsa 0.7.2", "sec1 0.3.0", - "sha2 0.10.7", + "sha2 0.10.8", "signature 1.6.4", "ssh-encoding", "zeroize", From 8bc2ce1c305b92939412480132c75106cbc799d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 21:39:40 +0000 Subject: [PATCH 097/102] chore(deps): bump webpki from 0.22.0 to 0.22.2 in /fuzz Bumps [webpki](https://github.com/briansmith/webpki) from 0.22.0 to 0.22.2. - [Commits](https://github.com/briansmith/webpki/commits) --- updated-dependencies: - dependency-name: webpki dependency-type: indirect ... Signed-off-by: dependabot[bot] --- fuzz/Cargo.lock | 54 ++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 89a93781c..feb204237 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -906,7 +906,7 @@ dependencies = [ [[package]] name = "deltachat" -version = "1.122.0" +version = "1.123.0" dependencies = [ "anyhow", "async-channel", @@ -1951,7 +1951,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.7", "tokio", "tower-service", "tracing", @@ -2089,7 +2089,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be" dependencies = [ - "socket2", + "socket2 0.4.7", "widestring", "winapi", "winreg 0.10.1", @@ -2383,14 +2383,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] @@ -2894,9 +2893,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -3139,7 +3138,7 @@ checksum = "641538578b21f5e5c8ea733b736895576d0fe329bb883b937db6f4d163dbaaf4" dependencies = [ "libc", "quinn-proto", - "socket2", + "socket2 0.4.7", "tracing", "windows-sys 0.42.0", ] @@ -3880,6 +3879,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "spin" version = "0.5.2" @@ -4166,22 +4175,21 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.25.0" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", - "memchr", "mio", "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.4", "tokio-macros", - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] @@ -4196,13 +4204,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", + "syn 2.0.15", ] [[package]] @@ -4258,9 +4266,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" dependencies = [ "bytes", "futures-core", @@ -4668,9 +4676,9 @@ dependencies = [ [[package]] name = "webpki" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +checksum = "07ecc0cd7cac091bf682ec5efa18b1cff79d617b84181f38b3951dbe135f607f" dependencies = [ "ring", "untrusted", From f3fb0dc5fed13c2c34a7de031b1131454c6aebe6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 21:44:49 +0000 Subject: [PATCH 098/102] chore(cargo): bump proptest from 1.2.0 to 1.3.1 Bumps [proptest](https://github.com/proptest-rs/proptest) from 1.2.0 to 1.3.1. - [Release notes](https://github.com/proptest-rs/proptest/releases) - [Changelog](https://github.com/proptest-rs/proptest/blob/master/CHANGELOG.md) - [Commits](https://github.com/proptest-rs/proptest/compare/v1.2.0...v1.3.1) --- updated-dependencies: - dependency-name: proptest dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd8fb284a..0ec49736a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3493,18 +3493,17 @@ dependencies = [ [[package]] name = "proptest" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65" +checksum = "7c003ac8c77cb07bb74f5f198bce836a689bcd5a42574612bf14d17bfd08c20e" dependencies = [ - "bitflags 1.3.2", - "byteorder", + "bitflags 2.3.3", "lazy_static", "num-traits", "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift", - "regex-syntax 0.6.29", + "regex-syntax 0.7.5", "unarray", ] From 0751cc50b9b634ec2ffe88fb7e9e6dec39f7db3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kl=C3=A4hn?= <39526136+Septias@users.noreply.github.com> Date: Sat, 14 Oct 2023 10:34:46 +0200 Subject: [PATCH 099/102] api(json-rpc): force stickers to be sent as stickers (#4819) This approach uses a param field to enable forcing the sticker `viewtype`. The first commit has the memory-only flag implemented, but this flag is not persistent through the database conversion needed for draft/undraft. That's why `param` has to be used. follow up to #4814 fixes #4739 --------- Co-authored-by: Septias --- deltachat-jsonrpc/src/api/mod.rs | 3 ++ src/chat.rs | 50 +++++++++++++++++++++++++++++++- src/message.rs | 6 ++++ src/param.rs | 3 ++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/deltachat-jsonrpc/src/api/mod.rs b/deltachat-jsonrpc/src/api/mod.rs index 6b9e8d5ff..e58adef60 100644 --- a/deltachat-jsonrpc/src/api/mod.rs +++ b/deltachat-jsonrpc/src/api/mod.rs @@ -1756,6 +1756,9 @@ impl CommandApi { let mut msg = Message::new(Viewtype::Sticker); msg.set_file(&sticker_path, None); + // JSON-rpc does not need heuristics to turn [Viewtype::Sticker] into [Viewtype::Image] + msg.force_sticker(); + let message_id = deltachat::chat::send_msg(&ctx, ChatId::new(chat_id), &mut msg).await?; Ok(message_id.to_u32()) } diff --git a/src/chat.rs b/src/chat.rs index 7687e554e..fe5cde406 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -2208,9 +2208,12 @@ async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> { .with_context(|| format!("attachment missing for message of type #{}", msg.viewtype))?; let mut maybe_sticker = msg.viewtype == Viewtype::Sticker; - if msg.viewtype == Viewtype::Image || maybe_sticker { + if msg.viewtype == Viewtype::Image + || maybe_sticker && !msg.param.exists(Param::ForceSticker) + { blob.recode_to_image_size(context, &mut maybe_sticker) .await?; + if !maybe_sticker { msg.viewtype = Viewtype::Image; } @@ -5679,6 +5682,51 @@ mod tests { .await } + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_sticker_jpeg_force() { + let alice = TestContext::new_alice().await; + let bob = TestContext::new_bob().await; + let alice_chat = alice.create_chat(&bob).await; + + let file = alice.get_blobdir().join("sticker.jpg"); + tokio::fs::write( + &file, + include_bytes!("../test-data/image/avatar1000x1000.jpg"), + ) + .await + .unwrap(); + + // Images without force_sticker should be turned into [Viewtype::Image] + let mut msg = Message::new(Viewtype::Sticker); + msg.set_file(file.to_str().unwrap(), None); + let sent_msg = alice.send_msg(alice_chat.id, &mut msg).await; + let msg = bob.recv_msg(&sent_msg).await; + assert_eq!(msg.get_viewtype(), Viewtype::Image); + + // Images with `force_sticker = true` should keep [Viewtype::Sticker] + let mut msg = Message::new(Viewtype::Sticker); + msg.set_file(file.to_str().unwrap(), None); + msg.force_sticker(); + let sent_msg = alice.send_msg(alice_chat.id, &mut msg).await; + let msg = bob.recv_msg(&sent_msg).await; + assert_eq!(msg.get_viewtype(), Viewtype::Sticker); + + // Images with `force_sticker = true` should keep [Viewtype::Sticker] + // even on drafted messages + let mut msg = Message::new(Viewtype::Sticker); + msg.set_file(file.to_str().unwrap(), None); + msg.force_sticker(); + alice_chat + .id + .set_draft(&alice, Some(&mut msg)) + .await + .unwrap(); + let mut msg = alice_chat.id.get_draft(&alice).await.unwrap().unwrap(); + let sent_msg = alice.send_msg(alice_chat.id, &mut msg).await; + let msg = bob.recv_msg(&sent_msg).await; + assert_eq!(msg.get_viewtype(), Viewtype::Sticker); + } + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_sticker_gif() -> Result<()> { test_sticker( diff --git a/src/message.rs b/src/message.rs index 7e86f8c99..c3e21b803 100644 --- a/src/message.rs +++ b/src/message.rs @@ -664,6 +664,12 @@ impl Message { self.viewtype } + /// Forces the message to **keep** [Viewtype::Sticker] + /// e.g the message will not be converted to a [Viewtype::Image]. + pub fn force_sticker(&mut self) { + self.param.set_int(Param::ForceSticker, 1); + } + /// Returns the state of the message. pub fn get_state(&self) -> MessageState { self.state diff --git a/src/param.rs b/src/param.rs index d0f3bb1aa..a9f5c1a42 100644 --- a/src/param.rs +++ b/src/param.rs @@ -187,6 +187,9 @@ pub enum Param { /// For Webxdc Message Instances: timestamp of summary update. WebxdcSummaryTimestamp = b'Q', + + /// For messages: Whether [crate::message::Viewtype::Sticker] should be forced. + ForceSticker = b'X', } /// An object for handling key=value parameter lists. From 16320357845da5cd963f7f3597c2ae18a2b8b6b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kl=C3=A4hn?= <39526136+Septias@users.noreply.github.com> Date: Sun, 15 Oct 2023 12:40:32 +0200 Subject: [PATCH 100/102] feat: add bot field to contact (#4821) closes #4647 --- src/contact.rs | 21 ++++++++++++++++++++- src/message.rs | 4 ++++ src/mimeparser.rs | 8 ++++++++ src/receive_imf.rs | 2 ++ src/sql/migrations.rs | 9 +++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/contact.rs b/src/contact.rs index ccf6b29c2..fed85e053 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -139,6 +139,15 @@ impl ContactId { pub const fn to_u32(&self) -> u32 { self.0 } + + /// Mark contact as bot. + pub(crate) async fn mark_bot(&self, context: &Context, is_bot: bool) -> Result<()> { + context + .sql + .execute("UPDATE contacts SET is_bot=? WHERE id=?;", (is_bot, self.0)) + .await?; + Ok(()) + } } impl fmt::Display for ContactId { @@ -223,6 +232,9 @@ pub struct Contact { /// Last seen message signature for this contact, to be displayed in the profile. status: String, + + /// If the contact is a bot. + is_bot: bool, } /// Possible origins of a contact. @@ -366,7 +378,7 @@ impl Contact { .sql .query_row_optional( "SELECT c.name, c.addr, c.origin, c.blocked, c.last_seen, - c.authname, c.param, c.status + c.authname, c.param, c.status, c.is_bot FROM contacts c WHERE c.id=?;", (contact_id,), @@ -379,6 +391,7 @@ impl Contact { let authname: String = row.get(5)?; let param: String = row.get(6)?; let status: Option = row.get(7)?; + let is_bot: bool = row.get(8)?; let contact = Self { id: contact_id, name, @@ -389,6 +402,7 @@ impl Contact { origin, param: param.parse().unwrap_or_default(), status: status.unwrap_or_default(), + is_bot, }; Ok(contact) }, @@ -498,6 +512,11 @@ impl Contact { Ok(()) } + /// Returns whether contact is a bot. + pub fn is_bot(&self) -> bool { + self.is_bot + } + /// Check if an e-mail address belongs to a known and unblocked contact. /// /// Known and unblocked contacts will be returned by `get_contacts()`. diff --git a/src/message.rs b/src/message.rs index c3e21b803..915c19af3 100644 --- a/src/message.rs +++ b/src/message.rs @@ -2339,6 +2339,8 @@ mod tests { let msg = alice.get_last_msg().await; assert_eq!(msg.get_text(), "hello".to_string()); assert!(msg.is_bot()); + let contact = Contact::get_by_id(&alice, msg.from_id).await?; + assert!(contact.is_bot()); // Alice receives a message from Bob who is not the bot anymore. receive_imf( @@ -2356,6 +2358,8 @@ mod tests { let msg = alice.get_last_msg().await; assert_eq!(msg.get_text(), "hello again".to_string()); assert!(!msg.is_bot()); + let contact = Contact::get_by_id(&alice, msg.from_id).await?; + assert!(!contact.is_bot()); Ok(()) } diff --git a/src/mimeparser.rs b/src/mimeparser.rs index b8b6b0a3a..b07e067df 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -113,7 +113,11 @@ pub(crate) struct MimeMessage { /// for e.g. late-parsing HTML. pub decoded_data: Vec, + /// Hop info for debugging. pub(crate) hop_info: String, + + /// Whether the contact sending this should be marked as bot. + pub(crate) is_bot: bool, } #[derive(Debug, PartialEq)] @@ -390,6 +394,9 @@ impl MimeMessage { signatures.clear(); } + // Auto-submitted is also set by holiday-notices so we also check `chat-version` + let is_bot = headers.contains_key("auto-submitted") && headers.contains_key("chat-version"); + let mut parser = MimeMessage { parts: Vec::new(), headers, @@ -418,6 +425,7 @@ impl MimeMessage { is_mime_modified: false, decoded_data: Vec::new(), hop_info, + is_bot, }; match partial { diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 14fa6f061..59442a118 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -379,6 +379,8 @@ pub(crate) async fn receive_imf_inner( .handle_reports(context, from_id, sent_timestamp, &mime_parser.parts) .await; + from_id.mark_bot(context, mime_parser.is_bot).await?; + Ok(Some(received_msg)) } diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index b358adb84..e8cc8a556 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -731,6 +731,15 @@ CREATE INDEX smtp_messageid ON imap(rfc724_mid); .await?; } + // Add is_bot column to contacts table with default false. + if dbversion < 102 { + sql.execute_migration( + "ALTER TABLE contacts ADD COLUMN is_bot INTEGER NOT NULL DEFAULT 0", + 102, + ) + .await?; + } + let new_version = sql .get_raw_config_int(VERSION_CFG) .await? From e87f785a0a958664bfdfca660d1b858de2357138 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 21 Oct 2023 04:18:39 +0000 Subject: [PATCH 101/102] test: adjust expected info message in test_verified_group_vs_delete_server_after Test was written for stable branch and has to be adjusted for verified 1:1 chats branch --- python/tests/test_0_complex_or_slow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/tests/test_0_complex_or_slow.py b/python/tests/test_0_complex_or_slow.py index 0c9256d98..75c554a6d 100644 --- a/python/tests/test_0_complex_or_slow.py +++ b/python/tests/test_0_complex_or_slow.py @@ -636,7 +636,7 @@ def test_verified_group_vs_delete_server_after(acfactory, tmp_path, lp): ac2_offl.start_io() msg_in = ac2_offl._evtracker.wait_next_incoming_message() assert not msg_in.is_system_message() - assert msg_in.text.startswith("[Sender of this message is not verified:") + assert msg_in.text.startswith("[The message was sent with non-verified encryption") ac2_offl_ac1_contact = msg_in.get_sender_contact() assert ac2_offl_ac1_contact.addr == ac1.get_config("addr") assert not ac2_offl_ac1_contact.is_verified() From 3748794048d6371ad775e75d589685ea0430f93b Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 25 Oct 2023 16:37:39 +0000 Subject: [PATCH 102/102] fix(sql): order migrations the same as on stable branch --- src/sql/migrations.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index a1815652f..6e69311c5 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -731,20 +731,20 @@ CREATE INDEX smtp_messageid ON imap(rfc724_mid); .await?; } - // Add is_bot column to contacts table with default false. if dbversion < 102 { sql.execute_migration( - "ALTER TABLE contacts ADD COLUMN is_bot INTEGER NOT NULL DEFAULT 0", + "CREATE TABLE download ( + msg_id INTEGER NOT NULL -- id of the message stub in msgs table + )", 102, ) .await?; } + // Add is_bot column to contacts table with default false. if dbversion < 103 { sql.execute_migration( - "CREATE TABLE download ( - msg_id INTEGER NOT NULL -- id of the message stub in msgs table - )", + "ALTER TABLE contacts ADD COLUMN is_bot INTEGER NOT NULL DEFAULT 0", 103, ) .await?;