mirror of
https://github.com/chatmail/core.git
synced 2026-09-21 12:39:12 +03:00
Compare commits
5 Commits
v1.138.0
...
link2xt/de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33134255ae | ||
|
|
b8c3b4593c | ||
|
|
d5af7b05d0 | ||
|
|
aad7a82549 | ||
|
|
fab6341dbb |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -85,7 +85,7 @@ jobs:
|
||||
- os: ubuntu-latest
|
||||
rust: 1.78.0
|
||||
- os: windows-latest
|
||||
rust: 1.78.0
|
||||
rust: 1.77.0
|
||||
- os: macos-latest
|
||||
rust: 1.78.0
|
||||
|
||||
|
||||
89
CHANGELOG.md
89
CHANGELOG.md
@@ -1,93 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## [1.138.0] - 2024-05-13
|
||||
|
||||
### API-Changes
|
||||
|
||||
- Add dc_msg_save_file() which saves file copy at the provided path ([#4309](https://github.com/deltachat/deltachat-core-rust/pull/4309)).
|
||||
- Api!(jsonrpc): replace EphemeralTimer tag "variant" with "kind"
|
||||
|
||||
### CI
|
||||
|
||||
- Use rsync instead of 3rd party github action.
|
||||
- Replace `black` with `ruff format`.
|
||||
- Update Rust to 1.78.0.
|
||||
|
||||
### Documentation
|
||||
|
||||
- Fix references in Message.set_location() documentation.
|
||||
- Remove Doxygen markup from Message.has_location().
|
||||
- Add `location` module documentation.
|
||||
|
||||
### Features / Changes
|
||||
|
||||
- Delete expired path locations in ephemeral loop.
|
||||
- Delete orphaned POI locations during housekeeping.
|
||||
- Parsing vCards for contacts sharing ([#5482](https://github.com/deltachat/deltachat-core-rust/pull/5482)).
|
||||
- contact-tools: Support parsing profile images from "PHOTO:data:image/jpeg;base64,...".
|
||||
- contact-tools: Add make_vcard().
|
||||
- Do not add location markers to messages with non-POI location.
|
||||
- Make one-to-one chats read-only the first seconds of a SecureJoin ([#5512](https://github.com/deltachat/deltachat-core-rust/pull/5512)).
|
||||
|
||||
### Fixes
|
||||
|
||||
- Message::set_file_from_bytes(): Set Param::Filename.
|
||||
- Do not fail to send encrypted quotes to unencrypted chats.
|
||||
- Never prepend subject to message text when bot receives it.
|
||||
- Interrupt location loop when new location is stored.
|
||||
- Correct message viewtype before recoding image blob ([#5496](https://github.com/deltachat/deltachat-core-rust/pull/5496)).
|
||||
- Delete POI location when disappearing message expires.
|
||||
- Delete non-POI locations after `delete_device_after`, not immediately.
|
||||
- Update special chats icons even if they are blocked ([#5509](https://github.com/deltachat/deltachat-core-rust/pull/5509)).
|
||||
- Use ChatIdBlocked::lookup_by_contact() instead of ChatId's method when applicable.
|
||||
|
||||
### Miscellaneous Tasks
|
||||
|
||||
- cargo: Bump quote from 1.0.35 to 1.0.36.
|
||||
- cargo: Bump base64 from 0.22.0 to 0.22.1.
|
||||
- cargo: Bump serde from 1.0.197 to 1.0.200.
|
||||
- cargo: Bump async-channel from 2.2.0 to 2.2.1.
|
||||
- cargo: Bump thiserror from 1.0.58 to 1.0.59.
|
||||
- cargo: Bump anyhow from 1.0.81 to 1.0.82.
|
||||
- cargo: Bump chrono from 0.4.37 to 0.4.38.
|
||||
- cargo: Bump imap-proto from 0.16.4 to 0.16.5.
|
||||
- cargo: Bump syn from 2.0.57 to 2.0.60.
|
||||
- cargo: Bump mailparse from 0.14.1 to 0.15.0.
|
||||
- cargo: Bump schemars from 0.8.16 to 0.8.19.
|
||||
|
||||
### Other
|
||||
|
||||
- Build ts docs with ci + nix.
|
||||
- Push docs to delta.chat instead of codespeak
|
||||
- Implement jsonrpc-docs build in github action
|
||||
- Rm unneeded rust install from ts docs ci
|
||||
- Correct folder for js.jsonrpc docs
|
||||
- Add npm install to upload-docs.yml
|
||||
- Add : to upload-docs.yml
|
||||
- Upload-docs npm run => npm run build
|
||||
- Rm leading slash
|
||||
- Rm npm install
|
||||
- Merge pull request #5515 from deltachat/dependabot/cargo/quote-1.0.36
|
||||
- Merge pull request #5522 from deltachat/dependabot/cargo/chrono-0.4.38
|
||||
- Merge pull request #5523 from deltachat/dependabot/cargo/mailparse-0.15.0
|
||||
- Add webxdc internal integration commands in jsonrpc ([#5541](https://github.com/deltachat/deltachat-core-rust/pull/5541))
|
||||
- Limit quote replies ([#5543](https://github.com/deltachat/deltachat-core-rust/pull/5543))
|
||||
- Stdio jsonrpc server npm package ([#5332](https://github.com/deltachat/deltachat-core-rust/pull/5332))
|
||||
|
||||
### Refactor
|
||||
|
||||
- python: Fix ruff 0.4.2 warnings.
|
||||
- Move `delete_poi_location` to location module and document it.
|
||||
- Remove allow_keychange.
|
||||
|
||||
### Tests
|
||||
|
||||
- Explain test_was_seen_recently false-positive and give workaround instructions ([#5474](https://github.com/deltachat/deltachat-core-rust/pull/5474)).
|
||||
- Test that member is added even if "Member added" is lost.
|
||||
- Test that POIs are deleted when ephemeral message expires.
|
||||
- Test ts build on branch
|
||||
|
||||
|
||||
## [1.137.4] - 2024-04-24
|
||||
|
||||
### API-Changes
|
||||
@@ -4071,4 +3983,3 @@ https://github.com/deltachat/deltachat-core-rust/pulls?q=is%3Apr+is%3Aclosed
|
||||
[1.137.2]: https://github.com/deltachat/deltachat-core-rust/compare/v1.137.1...v1.137.2
|
||||
[1.137.3]: https://github.com/deltachat/deltachat-core-rust/compare/v1.137.2...v1.137.3
|
||||
[1.137.4]: https://github.com/deltachat/deltachat-core-rust/compare/v1.137.3...v1.137.4
|
||||
[1.138.0]: https://github.com/deltachat/deltachat-core-rust/compare/v1.137.4...v1.138.0
|
||||
|
||||
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -1157,7 +1157,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat"
|
||||
version = "1.138.0"
|
||||
version = "1.137.4"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"anyhow",
|
||||
@@ -1250,7 +1250,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat-jsonrpc"
|
||||
version = "1.138.0"
|
||||
version = "1.137.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-channel 2.2.1",
|
||||
@@ -1274,7 +1274,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat-repl"
|
||||
version = "1.138.0"
|
||||
version = "1.137.4"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"anyhow",
|
||||
@@ -1289,7 +1289,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat-rpc-server"
|
||||
version = "1.138.0"
|
||||
version = "1.137.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"deltachat",
|
||||
@@ -1318,7 +1318,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat_ffi"
|
||||
version = "1.138.0"
|
||||
version = "1.137.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"deltachat",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat"
|
||||
version = "1.138.0"
|
||||
version = "1.137.4"
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
rust-version = "1.77"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat_ffi"
|
||||
version = "1.138.0"
|
||||
version = "1.137.4"
|
||||
description = "Deltachat FFI"
|
||||
edition = "2018"
|
||||
readme = "README.md"
|
||||
|
||||
@@ -7327,16 +7327,6 @@ void dc_event_unref(dc_event_t* event);
|
||||
/// Used in summaries.
|
||||
#define DC_STR_REACTED_BY 177
|
||||
|
||||
/// "Establishing guaranteed end-to-end encryption, please wait…"
|
||||
///
|
||||
/// Used as info message.
|
||||
#define DC_STR_SECUREJOIN_WAIT 190
|
||||
|
||||
/// "Could not yet establish guaranteed end-to-end encryption, but you may already send a message."
|
||||
///
|
||||
/// Used as info message.
|
||||
#define DC_STR_SECUREJOIN_WAIT_TIMEOUT 191
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat-jsonrpc"
|
||||
version = "1.138.0"
|
||||
version = "1.137.4"
|
||||
description = "DeltaChat JSON-RPC API"
|
||||
edition = "2021"
|
||||
default-run = "deltachat-jsonrpc-server"
|
||||
|
||||
@@ -346,14 +346,6 @@ pub enum SystemMessageType {
|
||||
LocationOnly,
|
||||
InvalidUnencryptedMail,
|
||||
|
||||
/// 1:1 chats info message telling that SecureJoin has started and the user should wait for it
|
||||
/// to complete.
|
||||
SecurejoinWait,
|
||||
|
||||
/// 1:1 chats info message telling that SecureJoin is still running, but the user may already
|
||||
/// send messages.
|
||||
SecurejoinWaitTimeout,
|
||||
|
||||
/// Chat ephemeral message timer is changed.
|
||||
EphemeralTimerChanged,
|
||||
|
||||
@@ -394,8 +386,6 @@ impl From<deltachat::mimeparser::SystemMessage> for SystemMessageType {
|
||||
SystemMessage::WebxdcStatusUpdate => SystemMessageType::WebxdcStatusUpdate,
|
||||
SystemMessage::WebxdcInfoMessage => SystemMessageType::WebxdcInfoMessage,
|
||||
SystemMessage::InvalidUnencryptedMail => SystemMessageType::InvalidUnencryptedMail,
|
||||
SystemMessage::SecurejoinWait => SystemMessageType::SecurejoinWait,
|
||||
SystemMessage::SecurejoinWaitTimeout => SystemMessageType::SecurejoinWaitTimeout,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -645,7 +635,7 @@ impl MessageInfo {
|
||||
#[derive(
|
||||
Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize, TypeDef, schemars::JsonSchema,
|
||||
)]
|
||||
#[serde(rename_all = "camelCase", tag = "kind")]
|
||||
#[serde(rename_all = "camelCase", tag = "variant")]
|
||||
pub enum EphemeralTimer {
|
||||
/// Timer is disabled.
|
||||
Disabled,
|
||||
|
||||
@@ -54,5 +54,5 @@
|
||||
},
|
||||
"type": "module",
|
||||
"types": "dist/deltachat.d.ts",
|
||||
"version": "1.138.0"
|
||||
"version": "1.137.4"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat-repl"
|
||||
version = "1.138.0"
|
||||
version = "1.137.4"
|
||||
license = "MPL-2.0"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/deltachat/deltachat-core-rust"
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "deltachat-rpc-client"
|
||||
version = "1.138.0"
|
||||
version = "1.137.4"
|
||||
description = "Python client for Delta Chat core JSON-RPC interface"
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat-rpc-server"
|
||||
version = "1.138.0"
|
||||
version = "1.137.4"
|
||||
description = "DeltaChat JSON-RPC server"
|
||||
edition = "2021"
|
||||
readme = "README.md"
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
{
|
||||
"license": "MPL-2.0",
|
||||
"main": "index.js",
|
||||
"name": "@deltachat/stdio-rpc-server",
|
||||
"optionalDependencies": {},
|
||||
"peerDependencies": {
|
||||
"@deltachat/jsonrpc-client": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"prepack": "node scripts/update_optional_dependencies_and_version.js"
|
||||
},
|
||||
"type": "module",
|
||||
"types": "index.d.ts",
|
||||
"version": "1.138.0"
|
||||
}
|
||||
"type": "module",
|
||||
"name": "@deltachat/stdio-rpc-server",
|
||||
"version": "1.137.4",
|
||||
"license": "MPL-2.0",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"scripts": {
|
||||
"prepack": "node scripts/update_optional_dependencies_and_version.js"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deltachat/jsonrpc-client": "*"
|
||||
}
|
||||
}
|
||||
@@ -266,8 +266,6 @@ module.exports = {
|
||||
DC_STR_REMOVE_MEMBER_BY_YOU: 130,
|
||||
DC_STR_REPLY_NOUN: 90,
|
||||
DC_STR_SAVED_MESSAGES: 69,
|
||||
DC_STR_SECUREJOIN_WAIT: 190,
|
||||
DC_STR_SECUREJOIN_WAIT_TIMEOUT: 191,
|
||||
DC_STR_SECURE_JOIN_GROUP_QR_DESC: 120,
|
||||
DC_STR_SECURE_JOIN_REPLIES: 118,
|
||||
DC_STR_SECURE_JOIN_STARTED: 117,
|
||||
|
||||
@@ -266,8 +266,6 @@ export enum C {
|
||||
DC_STR_REMOVE_MEMBER_BY_YOU = 130,
|
||||
DC_STR_REPLY_NOUN = 90,
|
||||
DC_STR_SAVED_MESSAGES = 69,
|
||||
DC_STR_SECUREJOIN_WAIT = 190,
|
||||
DC_STR_SECUREJOIN_WAIT_TIMEOUT = 191,
|
||||
DC_STR_SECURE_JOIN_GROUP_QR_DESC = 120,
|
||||
DC_STR_SECURE_JOIN_REPLIES = 118,
|
||||
DC_STR_SECURE_JOIN_STARTED = 117,
|
||||
|
||||
@@ -55,5 +55,5 @@
|
||||
"test:mocha": "mocha node/test/test.mjs --growl --reporter=spec --bail --exit"
|
||||
},
|
||||
"types": "node/dist/index.d.ts",
|
||||
"version": "1.138.0"
|
||||
"version": "1.137.4"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "deltachat"
|
||||
version = "1.138.0"
|
||||
version = "1.137.4"
|
||||
description = "Python bindings for the Delta Chat Core library using CFFI against the Rust-implemented libdeltachat"
|
||||
readme = "README.rst"
|
||||
requires-python = ">=3.7"
|
||||
|
||||
@@ -1 +1 @@
|
||||
2024-05-13
|
||||
2024-04-24
|
||||
117
src/chat.rs
117
src/chat.rs
@@ -12,7 +12,6 @@ use deltachat_contact_tools::{strip_rtlo_characters, ContactAddress};
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::EnumIter;
|
||||
use tokio::task;
|
||||
|
||||
use crate::aheader::EncryptPreference;
|
||||
use crate::blob::BlobObject;
|
||||
@@ -39,7 +38,6 @@ use crate::mimeparser::SystemMessage;
|
||||
use crate::param::{Param, Params};
|
||||
use crate::peerstate::Peerstate;
|
||||
use crate::receive_imf::ReceivedMsg;
|
||||
use crate::securejoin::BobState;
|
||||
use crate::smtp::send_msg_to_smtp;
|
||||
use crate::sql;
|
||||
use crate::stock_str;
|
||||
@@ -128,10 +126,6 @@ pub(crate) enum CantSendReason {
|
||||
|
||||
/// Not a member of the chat.
|
||||
NotAMember,
|
||||
|
||||
/// Temporary state for 1:1 chats while SecureJoin is in progress, after a timeout sending
|
||||
/// messages (incl. unencrypted if we don't yet know the contact's pubkey) is allowed.
|
||||
SecurejoinWait,
|
||||
}
|
||||
|
||||
impl fmt::Display for CantSendReason {
|
||||
@@ -151,7 +145,6 @@ impl fmt::Display for CantSendReason {
|
||||
write!(f, "mailing list does not have a know post address")
|
||||
}
|
||||
Self::NotAMember => write!(f, "not a member of the chat"),
|
||||
Self::SecurejoinWait => write!(f, "awaiting SecureJoin for 1:1 chat"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -617,10 +610,7 @@ impl ChatId {
|
||||
let sort_to_bottom = true;
|
||||
let ts = self
|
||||
.calc_sort_timestamp(context, timestamp_sent, sort_to_bottom, false)
|
||||
.await?
|
||||
// Always sort protection messages below `SystemMessage::SecurejoinWait{,Timeout}` ones
|
||||
// in case of race conditions.
|
||||
.saturating_add(1);
|
||||
.await?;
|
||||
self.set_protection_for_timestamp_sort(context, protect, ts, contact_id)
|
||||
.await
|
||||
}
|
||||
@@ -1417,18 +1407,6 @@ impl ChatId {
|
||||
|
||||
Ok(sort_timestamp)
|
||||
}
|
||||
|
||||
/// Spawns a task checking after a timeout whether the SecureJoin has finished for the 1:1 chat
|
||||
/// and otherwise notifying the user accordingly.
|
||||
pub(crate) fn spawn_securejoin_wait(self, context: &Context, timeout: u64) {
|
||||
let context = context.clone();
|
||||
task::spawn(async move {
|
||||
tokio::time::sleep(Duration::from_secs(timeout)).await;
|
||||
let chat = Chat::load_from_db(&context, self).await?;
|
||||
chat.check_securejoin_wait(&context, 0).await?;
|
||||
Result::<()>::Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ChatId {
|
||||
@@ -1608,12 +1586,6 @@ impl Chat {
|
||||
Some(ReadOnlyMailingList)
|
||||
} else if !self.is_self_in_chat(context).await? {
|
||||
Some(NotAMember)
|
||||
} else if self
|
||||
.check_securejoin_wait(context, constants::SECUREJOIN_WAIT_TIMEOUT)
|
||||
.await?
|
||||
> 0
|
||||
{
|
||||
Some(SecurejoinWait)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -1627,69 +1599,6 @@ impl Chat {
|
||||
Ok(self.why_cant_send(context).await?.is_none())
|
||||
}
|
||||
|
||||
/// Returns the remaining timeout for the 1:1 chat in-progress SecureJoin.
|
||||
///
|
||||
/// If the timeout has expired, notifies the user that sending messages is possible. See also
|
||||
/// [`CantSendReason::SecurejoinWait`].
|
||||
pub(crate) async fn check_securejoin_wait(
|
||||
&self,
|
||||
context: &Context,
|
||||
timeout: u64,
|
||||
) -> Result<u64> {
|
||||
if self.typ != Chattype::Single || self.protected != ProtectionStatus::Unprotected {
|
||||
return Ok(0);
|
||||
}
|
||||
let (mut param0, mut param1) = (Params::new(), Params::new());
|
||||
param0.set_cmd(SystemMessage::SecurejoinWait);
|
||||
param1.set_cmd(SystemMessage::SecurejoinWaitTimeout);
|
||||
let (param0, param1) = (param0.to_string(), param1.to_string());
|
||||
let Some((param, ts_sort, ts_start)) = context
|
||||
.sql
|
||||
.query_row_optional(
|
||||
"SELECT param, timestamp, timestamp_sent FROM msgs WHERE id=\
|
||||
(SELECT MAX(id) FROM msgs WHERE chat_id=? AND param IN (?, ?))",
|
||||
(self.id, ¶m0, ¶m1),
|
||||
|row| {
|
||||
let param: String = row.get(0)?;
|
||||
let ts_sort: i64 = row.get(1)?;
|
||||
let ts_start: i64 = row.get(2)?;
|
||||
Ok((param, ts_sort, ts_start))
|
||||
},
|
||||
)
|
||||
.await?
|
||||
else {
|
||||
return Ok(0);
|
||||
};
|
||||
if param == param1 {
|
||||
return Ok(0);
|
||||
}
|
||||
let now = time();
|
||||
// Don't await SecureJoin if the clock was set back.
|
||||
if ts_start <= now {
|
||||
let timeout = ts_start
|
||||
.saturating_add(timeout.try_into()?)
|
||||
.saturating_sub(now);
|
||||
if timeout > 0 {
|
||||
return Ok(timeout as u64);
|
||||
}
|
||||
}
|
||||
add_info_msg_with_cmd(
|
||||
context,
|
||||
self.id,
|
||||
&stock_str::securejoin_wait_timeout(context).await,
|
||||
SystemMessage::SecurejoinWaitTimeout,
|
||||
// Use the sort timestamp of the "please wait" message, this way the added message is
|
||||
// never sorted below the protection message if the SecureJoin finishes in parallel.
|
||||
ts_sort,
|
||||
Some(now),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
context.emit_event(EventType::ChatModified(self.id));
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
/// Checks if the user is part of a chat
|
||||
/// and has basically the permissions to edit the chat therefore.
|
||||
/// The function does not check if the chat type allows editing of concrete elements.
|
||||
@@ -2425,26 +2334,6 @@ pub(crate) async fn update_special_chat_names(context: &Context) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks if there is a 1:1 chat in-progress SecureJoin for Bob and, if necessary, schedules a task
|
||||
/// unblocking the chat and notifying the user accordingly.
|
||||
pub(crate) async fn resume_securejoin_wait(context: &Context) -> Result<()> {
|
||||
let Some(bobstate) = BobState::from_db(&context.sql).await? else {
|
||||
return Ok(());
|
||||
};
|
||||
if !bobstate.in_progress() {
|
||||
return Ok(());
|
||||
}
|
||||
let chat_id = bobstate.alice_chat();
|
||||
let chat = Chat::load_from_db(context, chat_id).await?;
|
||||
let timeout = chat
|
||||
.check_securejoin_wait(context, constants::SECUREJOIN_WAIT_TIMEOUT)
|
||||
.await?;
|
||||
if timeout > 0 {
|
||||
chat_id.spawn_securejoin_wait(context, timeout);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Handle a [`ChatId`] and its [`Blocked`] status at once.
|
||||
///
|
||||
/// This struct is an optimisation to read a [`ChatId`] and its [`Blocked`] status at once
|
||||
@@ -2698,9 +2587,7 @@ async fn prepare_msg_common(
|
||||
if let Some(reason) = chat.why_cant_send(context).await? {
|
||||
if matches!(
|
||||
reason,
|
||||
CantSendReason::ProtectionBroken
|
||||
| CantSendReason::ContactRequest
|
||||
| CantSendReason::SecurejoinWait
|
||||
CantSendReason::ProtectionBroken | CantSendReason::ContactRequest
|
||||
) && msg.param.get_cmd() == SystemMessage::SecurejoinMessage
|
||||
{
|
||||
// Send out the message, the securejoin message is supposed to repair the verification.
|
||||
|
||||
@@ -223,11 +223,6 @@ pub(crate) const DC_BACKGROUND_FETCH_QUOTA_CHECK_RATELIMIT: u64 = 12 * 60 * 60;
|
||||
/// in the group membership consistency algo to reject outdated membership changes.
|
||||
pub(crate) const TIMESTAMP_SENT_TOLERANCE: i64 = 60;
|
||||
|
||||
/// How long a 1:1 chat can't be used for sending while the SecureJoin is in progress. This should
|
||||
/// be 10-20 seconds so that we are reasonably sure that the app remains active and receiving also
|
||||
/// on mobile devices. See also [`crate::chat::CantSendReason::SecurejoinWait`].
|
||||
pub(crate) const SECUREJOIN_WAIT_TIMEOUT: u64 = 15;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
@@ -179,14 +179,6 @@ pub enum SystemMessage {
|
||||
/// which is sent by chatmail servers.
|
||||
InvalidUnencryptedMail = 13,
|
||||
|
||||
/// 1:1 chats info message telling that SecureJoin has started and the user should wait for it
|
||||
/// to complete.
|
||||
SecurejoinWait = 14,
|
||||
|
||||
/// 1:1 chats info message telling that SecureJoin is still running, but the user may already
|
||||
/// send messages.
|
||||
SecurejoinWaitTimeout = 15,
|
||||
|
||||
/// Self-sent-message that contains only json used for multi-device-sync;
|
||||
/// if possible, we attach that to other messages as for locations.
|
||||
MultiDeviceSync = 20,
|
||||
|
||||
@@ -29,7 +29,7 @@ mod bob;
|
||||
mod bobstate;
|
||||
mod qrinvite;
|
||||
|
||||
pub(crate) use bobstate::BobState;
|
||||
use bobstate::BobState;
|
||||
use qrinvite::QrInvite;
|
||||
|
||||
use crate::token::Namespace;
|
||||
@@ -764,7 +764,7 @@ mod tests {
|
||||
use crate::constants::Chattype;
|
||||
use crate::imex::{imex, ImexMode};
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::stock_str::{self, chat_protection_enabled};
|
||||
use crate::stock_str::chat_protection_enabled;
|
||||
use crate::test_utils::get_chat_msg;
|
||||
use crate::test_utils::{TestContext, TestContextManager};
|
||||
use crate::tools::SystemTime;
|
||||
@@ -961,7 +961,7 @@ mod tests {
|
||||
let expected_text = chat_protection_enabled(&alice).await;
|
||||
assert_eq!(msg.get_text(), expected_text);
|
||||
if case == SetupContactCase::CheckProtectionTimestamp {
|
||||
assert_eq!(msg.timestamp_sort, vc_request_with_auth_ts_sent + 1);
|
||||
assert_eq!(msg.timestamp_sort, vc_request_with_auth_ts_sent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -990,12 +990,10 @@ mod tests {
|
||||
|
||||
// Check Bob got the verified message in his 1:1 chat.
|
||||
let chat = bob.create_chat(&alice).await;
|
||||
let msg = get_chat_msg(&bob, chat.get_id(), 0, 2).await;
|
||||
let msg = get_chat_msg(&bob, chat.get_id(), 0, 1).await;
|
||||
assert!(msg.is_info());
|
||||
assert_eq!(msg.get_text(), stock_str::securejoin_wait(&bob).await);
|
||||
let msg = get_chat_msg(&bob, chat.get_id(), 1, 2).await;
|
||||
assert!(msg.is_info());
|
||||
assert_eq!(msg.get_text(), chat_protection_enabled(&bob).await);
|
||||
let expected_text = chat_protection_enabled(&bob).await;
|
||||
assert_eq!(msg.get_text(), expected_text);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
|
||||
@@ -9,11 +9,11 @@ use super::bobstate::{BobHandshakeStage, BobState};
|
||||
use super::qrinvite::QrInvite;
|
||||
use super::HandshakeMessage;
|
||||
use crate::chat::{is_contact_in_chat, ChatId, ProtectionStatus};
|
||||
use crate::constants::{self, Blocked, Chattype};
|
||||
use crate::constants::{Blocked, Chattype};
|
||||
use crate::contact::Contact;
|
||||
use crate::context::Context;
|
||||
use crate::events::EventType;
|
||||
use crate::mimeparser::{MimeMessage, SystemMessage};
|
||||
use crate::mimeparser::MimeMessage;
|
||||
use crate::sync::Sync::*;
|
||||
use crate::tools::{create_smeared_timestamp, time};
|
||||
use crate::{chat, stock_str};
|
||||
@@ -69,29 +69,7 @@ pub(super) async fn start_protocol(context: &Context, invite: QrInvite) -> Resul
|
||||
QrInvite::Contact { .. } => {
|
||||
// For setup-contact the BobState already ensured the 1:1 chat exists because it
|
||||
// uses it to send the handshake messages.
|
||||
let chat_id = state.alice_chat();
|
||||
// Calculate the sort timestamp before checking the chat protection status so that if we
|
||||
// race with its change, we don't add our message below the protection message.
|
||||
let sort_to_bottom = true;
|
||||
let ts_sort = chat_id
|
||||
.calc_sort_timestamp(context, 0, sort_to_bottom, false)
|
||||
.await?;
|
||||
if chat_id.is_protected(context).await? == ProtectionStatus::Unprotected {
|
||||
let ts_start = time();
|
||||
chat::add_info_msg_with_cmd(
|
||||
context,
|
||||
chat_id,
|
||||
&stock_str::securejoin_wait(context).await,
|
||||
SystemMessage::SecurejoinWait,
|
||||
ts_sort,
|
||||
Some(ts_start),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
chat_id.spawn_securejoin_wait(context, constants::SECUREJOIN_WAIT_TIMEOUT);
|
||||
}
|
||||
Ok(chat_id)
|
||||
Ok(state.alice_chat())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,15 +341,6 @@ impl BobState {
|
||||
async fn send_handshake_message(&self, context: &Context, step: BobHandshakeMsg) -> Result<()> {
|
||||
send_handshake_message(context, &self.invite, self.chat_id, step).await
|
||||
}
|
||||
|
||||
/// Returns whether we are waiting for a SecureJoin message from Alice, i.e. the protocol hasn't
|
||||
/// yet completed.
|
||||
pub(crate) fn in_progress(&self) -> bool {
|
||||
!matches!(
|
||||
self.next,
|
||||
SecureJoinStep::Terminated | SecureJoinStep::Completed
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends the requested handshake message to Alice.
|
||||
|
||||
30
src/sql.rs
30
src/sql.rs
@@ -8,7 +8,7 @@ use rusqlite::{config::DbConfig, types::ValueRef, Connection, OpenFlags, Row};
|
||||
use tokio::sync::{Mutex, MutexGuard, RwLock};
|
||||
|
||||
use crate::blob::BlobObject;
|
||||
use crate::chat::{self, add_device_msg, update_device_icon, update_saved_messages_icon};
|
||||
use crate::chat::{add_device_msg, update_device_icon, update_saved_messages_icon};
|
||||
use crate::config::Config;
|
||||
use crate::constants::DC_CHAT_ID_TRASH;
|
||||
use crate::context::Context;
|
||||
@@ -289,23 +289,21 @@ impl Sql {
|
||||
let passphrase_nonempty = !passphrase.is_empty();
|
||||
if let Err(err) = self.try_open(context, &self.dbfile, passphrase).await {
|
||||
self.close().await;
|
||||
return Err(err);
|
||||
}
|
||||
info!(context, "Opened database {:?}.", self.dbfile);
|
||||
*self.is_encrypted.write().await = Some(passphrase_nonempty);
|
||||
Err(err)
|
||||
} else {
|
||||
info!(context, "Opened database {:?}.", self.dbfile);
|
||||
*self.is_encrypted.write().await = Some(passphrase_nonempty);
|
||||
|
||||
// setup debug logging if there is an entry containing its id
|
||||
if let Some(xdc_id) = self
|
||||
.get_raw_config_u32(Config::DebugLogging.as_ref())
|
||||
.await?
|
||||
{
|
||||
set_debug_logging_xdc(context, Some(MsgId::new(xdc_id))).await?;
|
||||
// setup debug logging if there is an entry containing its id
|
||||
if let Some(xdc_id) = self
|
||||
.get_raw_config_u32(Config::DebugLogging.as_ref())
|
||||
.await?
|
||||
{
|
||||
set_debug_logging_xdc(context, Some(MsgId::new(xdc_id))).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
chat::resume_securejoin_wait(context)
|
||||
.await
|
||||
.log_err(context)
|
||||
.ok();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Changes the passphrase of encrypted database.
|
||||
|
||||
@@ -435,14 +435,6 @@ pub enum StockMessage {
|
||||
|
||||
#[strum(props(fallback = "%1$s reacted %2$s to \"%3$s\""))]
|
||||
MsgReactedBy = 177,
|
||||
|
||||
#[strum(props(fallback = "Establishing guaranteed end-to-end encryption, please wait…"))]
|
||||
SecurejoinWait = 190,
|
||||
|
||||
#[strum(props(
|
||||
fallback = "Could not yet establish guaranteed end-to-end encryption, but you may already send a message."
|
||||
))]
|
||||
SecurejoinWaitTimeout = 191,
|
||||
}
|
||||
|
||||
impl StockMessage {
|
||||
@@ -850,16 +842,6 @@ pub(crate) async fn secure_join_replies(context: &Context, contact_id: ContactId
|
||||
.replace1(&contact_id.get_stock_name(context).await)
|
||||
}
|
||||
|
||||
/// Stock string: `Establishing guaranteed end-to-end encryption, please wait…`.
|
||||
pub(crate) async fn securejoin_wait(context: &Context) -> String {
|
||||
translated(context, StockMessage::SecurejoinWait).await
|
||||
}
|
||||
|
||||
/// Stock string: `Could not yet establish guaranteed end-to-end encryption, but you may already send a message.`.
|
||||
pub(crate) async fn securejoin_wait_timeout(context: &Context) -> String {
|
||||
translated(context, StockMessage::SecurejoinWaitTimeout).await
|
||||
}
|
||||
|
||||
/// Stock string: `Scan to chat with %1$s`.
|
||||
pub(crate) async fn setup_contact_qr_description(
|
||||
context: &Context,
|
||||
|
||||
@@ -376,7 +376,7 @@ async fn test_old_message_2() -> Result<()> {
|
||||
SystemMessage::ChatProtectionEnabled
|
||||
);
|
||||
|
||||
// This creates protection-changed info message #2 with `timestamp_sort` greater by 1.
|
||||
// This creates protection-changed info message #2.
|
||||
let first_email = receive_imf(
|
||||
&alice,
|
||||
b"From: Bob <bob@example.net>\n\
|
||||
@@ -390,7 +390,8 @@ async fn test_old_message_2() -> Result<()> {
|
||||
.await?
|
||||
.unwrap();
|
||||
|
||||
// Both messages will get the same timestamp, so this one will be sorted under the previous one
|
||||
// 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,
|
||||
@@ -406,10 +407,7 @@ async fn test_old_message_2() -> Result<()> {
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(first_email.sort_timestamp, second_email.sort_timestamp);
|
||||
assert_eq!(
|
||||
first_email.sort_timestamp,
|
||||
protection_msg.timestamp_sort + 1
|
||||
);
|
||||
assert_eq!(first_email.sort_timestamp, protection_msg.timestamp_sort);
|
||||
|
||||
alice.golden_test_chat(chat.id, "test_old_message_2").await;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user