Commit Graph

488 Commits

Author SHA1 Message Date
link2xt
e78b509d0a chore: update rPGP from 0.18.0 to 0.19.0 2026-02-08 21:09:38 +00:00
Casper Zandbergen
63bf4c4f33 feat: allow clients to specify whether a call has video initially or not (#7740) 2026-02-04 16:49:32 +00:00
iequidoo
7c55356271 feat: MimeMessage: Put intended recipient fingerprints into signature 2026-01-26 18:27:36 -03:00
iequidoo
a67a5299bf Send and apply MDNs to self (#7005)
We currently synchronize "seen" status of messages by setting `\Seen` flag on IMAP and then looking
for new `\Seen` flags using `CONDSTORE` IMAP extension. This approach has multiple disadvantages:
- It requires that the server supports `CONDSTORE` extension. For example Maddy does not support
  CONDSTORE yet: https://github.com/foxcpp/maddy/issues/727
- It leaks the seen status to the server without any encryption.
- It requires more than just store-and-forward queues and prevents replacing IMAP with simpler
  protocols like POP3 or UUCP or some HTTP-based API for queue polling.

A simpler approach is to send MDNs to self when `Config::BccSelf` (aka multidevice) is enabled,
regardless of whether the message requested and MDN. If MDN was requested and we have MDNs enabled,
then also send to the message sender, but MDN to self is sent regardless of whether read receipts
are actually enabled.

`sync_seen_flags()` and `CONDSTORE` check is better completely removed, maybe after one
release. `store_seen_flags_on_imap()` can be kept for unencrypted non-chat messages.

One potential problem with sending MDNs is that it may trigger ratelimits on some providers and
count as another recipient.
2026-01-17 20:54:35 -03:00
Simon Laux
e1ebf3e96d refactor: don't use concat! in sql statements (#7720) 2026-01-15 22:44:53 +00:00
Simon Laux
2631745a57 feat: pre-messages / next version of download on demand (#7371)
Closes <https://github.com/chatmail/core/issues/7367>

Co-authored-by: iequidoo <dgreshilov@gmail.com>
Co-authored-by: Hocuri <hocuri@gmx.de>
2026-01-08 22:14:32 +00:00
link2xt
849cde9757 refactor: remove some easy to remove unwrap() calls 2025-11-19 17:38:58 +00:00
link2xt
72788daca0 refactor: use HashMap::extract_if() stabilized in Rust 1.88.0 2025-11-18 13:16:44 +00:00
link2xt
c6ace749e3 build: increase MSRV to 1.88.0
It is required by rPGP 0.18.0.

All the changes in `.rs` files are made automatically with `clippy --fix`.
2025-11-16 14:48:50 +00:00
iequidoo
1dbcd7f1f4 test: HP-Outer headers are added to messages with standard Header Protection (#7130) 2025-11-14 19:45:32 -03:00
iequidoo
e2ae6ae013 feat: mimeparser: Omit Legacy Display Elements (#7130)
Omit Legacy Display Elements from "text/plain" and "text/html" (implement 4.5.3.{2,3} of
https://www.rfc-editor.org/rfc/rfc9788 "Header Protection for Cryptographically Protected Email").
2025-11-14 19:45:32 -03:00
iequidoo
966ea28f83 feat: Ignore unprotected headers if Content-Type has "hp" parameter (#7130)
This is a part of implementation of https://www.rfc-editor.org/rfc/rfc9788 "Header Protection for
Cryptographically Protected Email".
2025-11-14 19:45:32 -03:00
link2xt
1cb0a25e16 fix: do not ignore I/O errors in BlobObject::store_from_base64 2025-11-08 20:06:45 +00:00
link2xt
cf5b145ce0 refactor: remove unused imports 2025-11-07 17:31:34 +00:00
link2xt
81ba2d20d6 fix: add device message instead of partial message when receive_imf fails 2025-11-05 14:11:27 +00:00
link2xt
9c2a13b88e refactor(sql): do not expose rusqlite Error type in query_map methods
We use query_and_then() instead of query_map() function now.
The difference is that row processing function
returns anyhow::Result, so simple fallible processing
like JSON parsing can be done inside of it
when calling query_map_vec() and query_map_collect()
without having to resort to query_map()
and iterating over all rows again afterwards.
2025-11-03 23:08:56 +00:00
Hocuri
5034449009 feat!: QR codes and symmetric encryption for broadcast channels (#7268)
Follow-up for https://github.com/chatmail/core/pull/7042, part of
https://github.com/chatmail/core/issues/6884.

This will make it possible to create invite-QR codes for broadcast
channels, and make them symmetrically end-to-end encrypted.

- [x] Go through all the changes in #7042, and check which ones I still
need, and revert all other changes
- [x] Use the classical Securejoin protocol, rather than the new 2-step
protocol
- [x] Make the Rust tests pass
- [x] Make the Python tests pass
- [x] Fix TODOs in the code
- [x] Test it, and fix any bugs I find
- [x] I found a bug when exporting all profiles at once fails sometimes,
though this bug is unrelated to channels:
https://github.com/chatmail/core/issues/7281
- [x] Do a self-review (i.e. read all changes, and check if I see some
things that should be changed)
- [x] Have this PR reviewed and merged
- [ ] Open an issue for "TODO: There is a known bug in the securejoin
protocol"
- [ ] Create an issue that outlines how we can improve the Securejoin
protocol in the future (I don't have the time to do this right now, but
want to do it sometime in winter)
- [ ] Write a guide for UIs how to adapt to the changes (see
https://github.com/deltachat/deltachat-android/pull/3886)

## Backwards compatibility

This is not very backwards compatible:
- Trying to join a symmetrically-encrypted broadcast channel with an old
device will fail
- If you joined a symmetrically-encrypted broadcast channel with one
device, and use an old core on the other device, then the other device
will show a mostly empty chat (except for two device messages)
- If you created a broadcast channel in the past, then you will get an
error message when trying to send into the channel:

> The up to now "experimental channels feature" is about to become an officially supported one. By that, privacy will be improved, it will become faster, and less traffic will be consumed.
> 
> As we do not guarantee feature-stability for such experiments, this means, that you will need to create the channel again. 
> 
> Here is what to do:
>  • Create a new channel
>  • Tap on the channel name
>  • Tap on "QR Invite Code"
>  • Have all recipients scan the QR code, or send them the link
> 
> If you have any questions, please send an email to delta@merlinux.eu or ask at https://support.delta.chat/.


## The symmetric encryption

Symmetric encryption uses a shared secret. Currently, we use AES128 for
encryption everywhere in Delta Chat, so, this is what I'm using for
broadcast channels (though it wouldn't be hard to switch to AES256).

The secret shared between all members of a broadcast channel has 258
bits of entropy (see `fn create_broadcast_shared_secret` in the code).

Since the shared secrets have more entropy than the AES session keys,
it's not necessary to have a hard-to-compute string2key algorithm, so,
I'm using the string2key algorithm `salted`. This is fast enough that
Delta Chat can just try out all known shared secrets. [^1] In order to
prevent DOS attacks, Delta Chat will not attempt to decrypt with a
string2key algorithm other than `salted` [^2].

## The "Securejoin" protocol that adds members to the channel after they
scanned a QR code

This PR uses the classical securejoin protocol, the same that is also
used for group and 1:1 invitations.

The messages sent back and forth are called `vg-request`,
`vg-auth-required`, `vg-request-with-auth`, and `vg-member-added`. I
considered using the `vc-` prefix, because from a protocol-POV, the
distinction between `vc-` and `vg-` isn't important (as @link2xt pointed
out in an in-person discussion), but
1. it would be weird if groups used `vg-` while broadcasts and 1:1 chats
used `vc-`,
2. we don't have a `vc-member-added` message yet, so, this would mean
one more different kind of message
3. we anyways want to switch to a new securejoin protocol soon, which
will be a backwards incompatible change with a transition phase. When we
do this change, we can make everything `vc-`.



[^1]: In a symmetrically encrypted message, it's not visible which
secret was used to encrypt without trying out all secrets. If this does
turn out to be too slow in the future, then we can remember which secret
was used more recently, and and try the most recent secret first. If
this is still too slow, then we can assign a short, non-unique (~2
characters) id to every shared secret, and send it in cleartext. The
receiving Delta Chat will then only try out shared secrets with this id.
Of course, this would leak a little bit of metadata in cleartext, so, I
would like to avoid it.
[^2]: A DOS attacker could send a message with a lot of encrypted
session keys, all of which use a very hard-to-compute string2key
algorithm. Delta Chat would then try to decrypt all of the encrypted
session keys with all of the known shared secrets. In order to prevent
this, as I said, Delta Chat will not attempt to decrypt with a
string2key algorithm other than `salted`

BREAKING CHANGE: A new QR type AskJoinBroadcast; cloning a broadcast
channel is no longer possible; manually adding a member to a broadcast
channel is no longer possible (only by having them scan a QR code)
2025-11-03 21:02:13 +01:00
iequidoo
7f059140be docs: Comment why spaced en dash is used to separate message Subject from text 2025-11-01 14:06:55 -03:00
link2xt
5f3948b462 refactor(sql): add query_map_vec()
This also replaces some cases where flatten()
was used, effectively ignoring the errors.
2025-10-24 18:17:15 +00:00
Hocuri
9897ef2e9b refactor: Remove error stock strings that are rarely used these days (#7327)
This removes the DC_STR_CANTDECRYPT_MSG_BODY and
DC_STR_CANT_DECRYPT_OUTGOING_MSGS stock strings.

See
https://github.com/deltachat/deltachat-android/pull/3956#issuecomment-3425349195
for reasoning.
2025-10-21 09:04:11 +00:00
link2xt
8070dfcc82 refactor(mimeparser): store only one signature fingerprint
Messages are normally not signed with more than one key
and in this case we pick an arbitrary signature later anyway.
2025-10-15 16:45:36 +00:00
Simon Laux
af58b86b60 refactor: Use variables directly in formatted strings (#7284)
made with `cargo clippy --all --fix` then manually reviewed to ensure
this was the only thing that changed.
2025-10-09 15:26:59 +00:00
link2xt
23bfa4fc43 api!: remove APIs for video chat invitations 2025-10-05 12:19:10 +00:00
link2xt
c2ea2cda4c feat: make text/calendar alternative available as an attachment 2025-10-02 09:15:25 +00:00
link2xt
af69756df0 fix: prefer last part in multipart/alternative
This is recommended by RFC 2046
and does not require a separate loop
looking for multipart subpart.
2025-10-02 02:20:17 +00:00
iequidoo
f94b2c3794 feat: Don't ignore receive_imf_inner() errors, try adding partially downloaded message instead (#7196)
Ignoring `receive_imf_inner()` errors, i.e. silently skipping messages on failures, leads to bugs
never fixed. As for temporary I/O errors, ignoring them leads to lost messages, in this case it's
better to bubble up the error and get the IMAP loop stuck. However if there's some logic error, it's
better to show it to the user so that it's more likely reported, and continue receiving messages. To
distinguish these cases, on error, try adding the message as partially downloaded with the error set
to `msgs.error`, this way the user also can retry downloading the message to finally see it if the
problem is fixed.
2025-09-30 00:54:24 -03:00
iequidoo
7477ebbdd7 fix: Take the last valid Autocrypt header (#7167)
DKIM-Signatures apply to the last headers, so start from the last header and take a valid one,
i.e. skip headers having unknown critical attributes, etc. Though this means that Autocrypt header
must be "oversigned" to guarantee that a not DKIM-signed header isn't taken, still start from the
last header for consistency with processing other headers. This isn't a security issue anyway.
2025-09-22 15:38:32 -03:00
link2xt
53a3e51920 feat: support receiving Autocrypt-Gossip with _verified attribute
This commit is a preparation for
sending Autocrypt-Gossip with `_verified` attribute
instead of `Chat-Verified` header.
2025-09-04 19:46:14 +00:00
bjoern
bed1623dcb feat: use dedicated 'call' viewtype (#7174)
a dedicated viewtype allows the UI to show a more advanced UI, but even
when using the defaults,
it has the advantage that incoming/outgoing and the date are directly
visible.

successor of https://github.com/chatmail/core/pull/6650
2025-09-04 16:51:51 +02:00
link2xt
d4704977bc api!: remove e2ee_enabled preference
The setting is already removed from the UIs,
but users who had it disabled previously have
no way to enable it. After this change
encryption is effectively always preferred.
2025-09-04 13:58:05 +00:00
link2xt
7ea6ca35d7 feat: do not replace messages with an error on verification failure 2025-09-02 18:29:53 +00:00
bjoern
0bbd910883 feat: add call ringing API (#6650)
this PR adds a "ringing" api that can be used for calls later.

see deltachat.h for details about the API; jsonrpc is left out until
things are settled for the needs of android/iOS

UI using this PR already successfully are
https://github.com/deltachat/deltachat-ios/pull/2638 and
https://github.com/deltachat/deltachat-android/pull/3785 ; the "payload"
passed forth and back is optimised for
https://github.com/deltachat/calls-webapp

---------

Co-authored-by: l <link2xt@testrun.org>
2025-08-30 23:48:38 +02:00
link2xt
3656337d41 refactor: do not return Result from valid_signature_fingerprints()
This function never fails.
2025-08-18 07:47:34 +00:00
link2xt
a89b6321f1 feat: assign messages to key-contacts based on Issuer Fingerprint 2025-08-16 23:22:35 +00:00
link2xt
b431206ede fix: allow receiving empty files 2025-08-06 13:33:04 +00:00
bjoern
2c7d51f98f feat: add "e2ee encrypted" info message to all e2ee chats (#7008)
this PR adds a info message "messages are end-to-end-encrypted" also for
chats created by eg. vcards. by the removal of lock icons, this is a
good place to hint for that in addition; this is also what eg. whatsapp
and others are doing

the wording itself is tweaked at
https://github.com/deltachat/deltachat-android/pull/3817 (and there is
also the rough idea to make the message a little more outstanding, by
some more dedicated colors)

~~did not test in practise, if this leads to double "e2ee info messages"
on secure join, tests look good, however.~~ EDIT: did lots of practise
tests meanwhile :)

most of the changes in this PR are about test ...

ftr, in another PR, after 2.0 reeases, there could probably quite some
code cleanup wrt set-protection, protection-disabled etc.

---------

Co-authored-by: Hocuri <hocuri@gmx.de>
2025-07-18 22:08:33 +02:00
iequidoo
6d8dff54a7 fix: Ignore protected headers in outer message part (#6357)
Delta Chat always adds protected headers to the inner encrypted or signed message, so if a protected
header is only present in the outer part, it should be ignored because it's probably added by the
server or somebody else. The exceptions are Subject and List-ID because there are known cases when
they are only present in the outer message part.

Also treat any Chat-* headers as protected. This fixes e.g. a case when the server injects a
"Chat-Version" IMF header tricking Delta Chat into thinking that it's a chat message.

Also handle "Auto-Submitted" and "Autocrypt-Setup-Message" as protected headers on the receiver
side, this was apparently forgotten.
2025-07-16 11:39:06 -03:00
link2xt
e6fd52afff fix: always prefer the last header
Headers are normally added at the top of the message,
e.g. when forwarding new `Received` headers are
added at the top.

When headers are protected with DKIM-Signature
and oversigning is not used,
forged headers may be added on top
so headers from the top are generally less trustworthy.

This is tested with `test_take_last_header`,
but so far last header was only preferred
for known headers. This change extends
preference of the last header to all headers.
2025-07-14 14:57:52 +00:00
ivn
22258f7269 fix!: Use Viewtype::File for messages with invalid images, images of unknown size, images > 50 Mpx (#6825)
BREAKING CHANGE: messages with invalid images, images of unknown size,
huge images, will have Viewtype::File

After changing the logic of Viewtype selection, I had to fix 3 old tests
that used invalid Base64 image data.

Co-authored-by: iequidoo <117991069+iequidoo@users.noreply.github.com>
2025-07-10 18:11:55 -03:00
iequidoo
acba27a328 fix: Treat and send images that can't be decoded as Viewtype::File
Otherwise unsupported and corrupted images are displayed in the "Images" tab in UIs and that looks
as a Delta Chat bug. This should be a rare case though, so log it as error and let the user know
that metadata isn't removed from the image at least.
2025-07-08 17:43:13 -03:00
Hocuri
c9c5d94666 fix: Prefer encrypted List-Id header (#6983)
If there is an encrypted List-Id header, it should be preferred over an
unencrypted List-Id header.

Part of #6884
2025-07-07 20:45:21 +00:00
link2xt
5c3de759d3 refactor: upgrade to Rust 2024 2025-06-28 17:07:59 +00:00
link2xt
416131b4a2 feat: key-contacts
This change introduces a new type of contacts
identified by their public key fingerprint
rather than an e-mail address.

Encrypted chats now stay encrypted
and unencrypted chats stay unencrypted.
For example, 1:1 chats with key-contacts
are encrypted and 1:1 chats with address-contacts
are unencrypted.
Groups that have a group ID are encrypted
and can only contain key-contacts
while groups that don't have a group ID ("adhoc groups")
are unencrypted and can only contain address-contacts.

JSON-RPC API `reset_contact_encryption` is removed.
Python API `Contact.reset_encryption` is removed.
"Group tracking plugin" in legacy Python API was removed because it
relied on parsing email addresses from system messages with regexps.

Co-authored-by: Hocuri <hocuri@gmx.de>
Co-authored-by: iequidoo <dgreshilov@gmail.com>
Co-authored-by: B. Petersen <r10s@b44t.com>
2025-06-26 14:07:39 +00:00
link2xt
545007aca5 api!: make logging macros private 2025-06-21 11:01:25 +00:00
Friedel Ziegelmayer
5c2af42cdd build: update to rPGP 0.16.0 (#6719)
Co-authored-by: Heiko Schaefer <heiko@schaefer.name>
Co-authored-by: link2xt <link2xt@testrun.org>
2025-05-29 13:06:18 +00:00
link2xt
a68ddab703 chore: apply beta clippy fixes 2025-05-20 14:09:07 +00:00
iequidoo
49c300d2ac test: Check headers absense straightforwardly
In the `test` cfg, introduce `MimeMessage::headers_removed` hash set and `header_exists()` function
returning whether the header exists in any part of the parsed message. `get_header()` shouldn't be
used in tests for checking absense of headers because it returns `None` for removed ("ignored")
headers.
2025-04-12 23:24:54 -03:00
link2xt
8fd972a2f9 fix: use protected Date with protected Autocrypt 2025-03-18 05:44:33 +00:00
link2xt
ef008d4ca0 fix: use protected Date header for signed messages 2025-03-16 16:08:46 +00:00
iequidoo
82f61035d4 fix: Prefer hidden Message-ID header if any
Delta Chat already adds hidden Message-ID header because some servers mess up with it, so it should
be preferred.
2025-03-13 19:52:33 -03:00