Commit Graph

284 Commits

Author SHA1 Message Date
link2xt
10b93b3943 refactor: enable clippy::arithmetic_side_effects lint 2026-02-17 16:01:16 +00:00
iequidoo
7c55356271 feat: MimeMessage: Put intended recipient fingerprints into signature 2026-01-26 18:27:36 -03:00
Hocuri
d446a16fc6 Sync broadcast subscribers list (#7578)
fix #7497
2026-01-13 15:04:51 +01:00
link2xt
14a59afd5d fix: do not rely on Secure-Join header to detect {vc,vg}-request 2026-01-07 15:47:16 +00:00
link2xt
25750de4e1 feat: send sync messages over SMTP and do not move them to mvbox 2025-12-26 10:58:33 +00:00
link2xt
0defa117a0 refactor: use u16 instead of usize to represent progress bar 2025-12-07 13:23:31 +00:00
Hocuri
0d0602a4a5 fix: Sort system messages to the bottom of the chat
Fix #7435

For most messages, `calc_sort_timestamp()` makes sure that they are at the correct place; esp. that they are not above system messages or other noticed/seen messages.

Most callers of `add_info_msg()`, however, didn't call `calc_sort_timestamp()`, and just used `time()` or `smeared_time()` to get the sort timestamp. Because of this, system messages could sometimes wrongly be sorted above other messages.

This PR fixes this by making the sort timestamp optional in `add_info_msg*()`. If the sort timestamp isn't passed, then the message is sorted to the bottom of the chat. `sent_rcvd_timestamp` is not optional anymore, because we need _some_ timestamp that can be shown to the user (most callers just pass `time()` there).
2025-11-18 18:58:26 +01:00
iequidoo
fdea6c8af3 feat: Error toast for "Not creating securejoin QR for old broadcast" 2025-11-08 16:23:15 -03:00
link2xt
cf5b145ce0 refactor: remove unused imports 2025-11-07 17:31:34 +00:00
Hocuri
a40fd288fc fix: add info message if user tries to create a QR code for deprecated channel (#7399)
Fix https://github.com/chatmail/core/issues/7397:
- Don't allow creating a QR code for such old channels.
2025-11-05 17:16:54 +01:00
Hocuri
f04c881b8c feat: Put self-name into group invite codes (#7398)
Fix https://github.com/chatmail/core/issues/7015 by putting the
self-name into invite codes for group and broadcast channels.

The self-name will be truncated to 16 characters.
2025-11-04 23:17:54 +01:00
bjoern
ee6b9075aa slightly nicer and shorter QR and invite codes (#7390)
- sort garbage to the beginning, readable text to the end
- instead of `%20`, make use of `+` to encode spaces
- shorter invite links and smaller QR codes by truncation of the names

the truncation of the name uses chars() which does not respect grapheme clusters, so
that last character may be wrong. not sure if there is a nice and easy
alternative, but maybe it's good engoug - the real, full name will come
over the wire (exiting truncate() truncates on word boundaries, which is
maybe too soft here - names may be long, depending on the language, and
not contain any space)

moreover, this resolves the "name too long" issue from
https://github.com/chatmail/core/issues/7015

---------

Co-authored-by: Hocuri <hocuri@gmx.de>
2025-11-04 22:01:24 +01: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
Hocuri
19d7799324 feat: Be more generous with marking contacts as verified for now (#7336)
Context: PR #7116 is backwards-incompatible with versions older than
v2.21, and since the release hasn't reached all users yet, we currently
can't release from main; for details see #7326.

Issue #7326 explains how we can make this less breaking, but this only
works if many contacts are verified. So, this PR here proposes to
postpone the stricter rules for who is verified a bit:

- Set verification timeout for invite codes to 1 week (this is still
stricter than no timeout at all, which we had in the past)
- Don't reset indirect verifications yet

In a few months (when everyone has v2.22.0), we can revert the PR here,
then.

---------

Co-authored-by: l <link2xt@testrun.org>
2025-10-24 18:07:29 +00:00
Hocuri
51b9e86d71 Opt-in weekly sending of statistics (#6851)
This way, the statistics / self-reporting bot will be made into an
opt-in regular sending of statistics, where you enable the setting once
and then they will be sent automatically. The statistics will be sent to
a bot, so that the user can see exactly which data is being sent, and
how often. The chat will be archived and muted by default, so that it
doesn't disturb the user.

The collected statistics will focus on the public-key-verification that
is performed while scanning a QR code. Later on, we can add more
statistics to collect.

**Context:**

_This is just to give a rough idea; I would need to write a lot more
than a few paragraphs in order to fully explain all the context here_.

End-to-end encrypted messengers are generally susceptible to MitM
attacks. In order to mitigate against this, messengers offer some way of
verifying the chat partner's public key. However, numerous studies found
that most popular messengers implement this public-key-verification in a
way that is not understood by users, and therefore ineffective - [a 2021
"State of Knowledge" paper
concludes:](https://dl.acm.org/doi/pdf/10.1145/3558482.3581773)

> Based on our evaluation, we have determined that all current E2EE
apps, particularly when operating in opportunistic E2EE mode, are
incapable of repelling active man-in-the-middle (MitM) attacks. In
addition, we find that none of the current E2EE apps provide better and
more usable [public key verification] ceremonies, resulting in insecure
E2EE communications against active MitM attacks.

This is why Delta Chat tries to go a different route: When the user
scans a QR code (regardless of whether the QR code creates a 1:1 chat,
invites to a group, or subscribes to a broadcast channel), a
public-key-verification is performed in the background, without the user
even having to know about this.

The statistics collected here are supposed to tell us whether Delta Chat
succeeds to nudge the users into using QR codes in a way that is secure
against MitM attacks.

**Plan for statistics-sending:**

- [x] Get this PR reviewed and merged (but don't make it available in
the UI yet; if Android wants to make a release in the meantime, I will
create a PR that removes the option there)
- [x] Set the interval to 1 week again (right now, it's 1 minute for
testing)
- [ ] Write something for people who are interested in what exactly we
count, and link to it (see `TODO[blog post]` in the code)
- [ ] Prepare a short survey for participants
- [ ] Fine-tune the texts at
https://github.com/deltachat/deltachat-android/pull/3794, and get it
reviewed and merged
- [ ] After the next release, ask people to enable the
statistics-sending
2025-10-21 15:29:21 +02:00
link2xt
6c24edb40d feat: do not mark Bob as verified if auth token is old 2025-10-19 11:35:09 +00:00
link2xt
498a831873 api!: remove APIs to create protected chats
Create unprotected group in test_create_protected_grp_multidev
The test is renamed accordingly.

SystemMessage::ChatE2ee is added in encrypted groups
regardless of whether they are protected or not.
Previously new encrypted unprotected groups
had no message saying that messages are end-to-end encrypted
at all.
2025-10-19 11:35:09 +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
link2xt
a506e2d5a2 api: add chat ID to SecureJoinInviterProgress 2025-09-23 23:23:21 +00:00
link2xt
4c66518a68 docs: SecurejoinInviterProgress never returns an error 2025-09-23 23:23:21 +00:00
link2xt
40b866117e fix: ignore vc-/vg- prefix for SecurejoinInviterProgress
Inviter progress is for group if we added Bob to the group,
not if Bob sent us vg-request-with-auth.
2025-09-16 18:00:15 +00:00
link2xt
cb5f9f3051 api!: get rid of inviter progress other than 0 and 1000
UIs don't display a dialog with a progress bar anyway.
2025-09-16 18:00:15 +00:00
link2xt
80f97cf9bd fix: create 1:1 chat only if auth token is for setup contact
Previously we trusted Bob to send the correct vc- or vg- prefix.
2025-09-16 18:00:15 +00:00
Hocuri
1cc7ce6e27 api: Put the chattype into the SecurejoinInviterProgress event (#7181)
Quoting @adbenitez:

> I have been using the SecurejoinInviterProgress event to show a
welcome message when user scan the QR/link of the bot (== starts a chat
with the bot)

> but this have a big problem: in that event all you know is that a
contact completed the secure-join process, you don't know if it was via
certain 1:1 invite link or a group invitation, then a group-invite bot
would send you a help message in 1:1 every time you join a group with it

Since it's easy enough to add this information to the
SecurejoinInviterProgress event, I wrote a PR to do so.
2025-09-09 08:17:53 +00: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
iequidoo
61633cf23b fix: Don't reverify contacts by SELF on receipt of a message from another device
Also verify not yet verified contacts w/o setting a verifier for them (in the db it's stored as
`verifier_id=id` though) because we don't know who verified them for another device.
2025-09-01 05:09:19 -03:00
iequidoo
dbdf5f2746 feat: get_securejoin_qr(): Log error if group doesn't have grpid
This doesn't fix anything in UIs currently because they don't call `get_securejoin_qr()` for
unencrypted groups, but it's still better to log an error which will be shown in this case.
2025-08-12 19:59:00 -03:00
iequidoo
58b99f59f7 feat: Log failed debug assertions in all configurations
Add `logged_debug_assert` macro logging a warning if a condition is not satisfied, before invoking
`debug_assert!`, and use this macro where `Context` is accessible (i.e. don't change function
signatures for now).
Follow-up to 0359481ba4.
2025-07-12 07:27:55 -03: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
Hocuri
a981573e48 fix: Fix order of operations when handling "vc-request-with-auth" (#6850) 2025-05-12 16:52:10 +02:00
link2xt
1ebaa2a718 feat(securejoin): do not create 1:1 chat on Alice's side until vc-request-with-auth
vc-request is an unencrypted message
that Bob sends when he does not have Alice's key.
It also does not contain
Bob's avatar and name,
so the contact has only the email address
at this point and it is too early
to show it.
2025-03-24 14:21:56 +00:00
link2xt
bbb267331c feat: allow scanning multiple securejoin QR codes in parallel 2025-02-20 18:25:45 +00:00
Hocuri
0c0afead2c refactor: Move even more tests into their own files (#6521)
As always, I moved the tests from the biggest files. I left out
`mimefactory.rs` because @link2xt has an active PR modifying the tests.
2025-02-06 22:37:25 +01:00
iequidoo
f61d5af468 feat: Delete vg-request-with-auth from IMAP after processing (#6208)
In multi-device case `vg-request-with-auth` left on IMAP may result in situation when Bob joins the
group, then leaves it, then second Alice device comes online and processes `vg-request-with-auth`
again and adds Bob back. So we should IMAP-delete `vg-request-with-auth`. Another device will know
the Bob's key from Autocrypt-Gossip. It's not a problem if Alice loses state (restores from an old
backup) or goes offline for long before sending `vg-member-added`, anyway it may not be delivered by
the server, rather Bob should retry sending SecureJoin messages as he is a part which wants to join,
so let's not solve this for now.
2024-12-25 14:47:17 -03:00
Hocuri
39be59172d test: Notifiy more prominently & in more tests about false positives when running cargo test (#6308)
This PR:
- Moves the note about the false positive to the end of the test output,
where it is more likely to be noticed
- Also notes in test_modify_chat_disordered() and
test_setup_contact_*(), in addition to the existing note in
test_was_seen_recently()
2024-12-06 15:07:57 +01:00
Hocuri
95ac7647ac test: Mark receive_imf() as only for tests and "internals" feature (#6235)
`receive_imf() is only used in tests and the REPL, which enables the
"internals" feature. This PR marks it as such, so that it's clear not
only from the comment that this function is not used for anything else.
2024-11-21 14:57:35 +01:00
Sebastian Klähn
8f3be764d2 change: Use i.delta.chat in qr codes (#6223)
As discussed in #5467 we want to use `i.delta.chat` in QR codes in favor
of `OPENPGP4FPR:` scheme. This PR does the replacement in
`get_securejoin_qr` which is used in `get_securejoin_qr_svg`.

close #5467
2024-11-19 17:32:42 +01:00
link2xt
c18a476806 refactor: forbid clippy::string_slice 2024-11-18 23:57:57 +00:00
link2xt
7b1fa50fb0 refactor: remove unused allow(clippy::indexing_slicing) 2024-11-18 21:58:48 +00:00
link2xt
e7a29f0aa7 chore(cargo): update rPGP from 0.13.2 to 0.14.0 2024-11-14 09:31:40 +00:00
iequidoo
bea7e4792c fix: Save contact name from SecureJoin QR to authname, not to name (#6115)
3f9242a saves name from all QR codes to `name` (i.e. manually edited name), but for SecureJoin QR
codes the name should be saved to `authname` because such QR codes are generated by the
inviter. Other QR codes may be generated locally and not only by Delta Chat, so the name from them
mustn't go to `authname` and be revealed to the network or other contacts.
2024-11-01 12:34:24 -03:00
link2xt
e32d676a08 fix: normalize proxy URLs before saving into proxy_url 2024-10-24 16:43:10 +00:00
link2xt
aa71fbe04c refactor: resultify get_self_fingerprint() 2024-10-21 13:03:58 +00:00
Hocuri
5711f2fe3a feat: More context for the "Cannot establish guaranteed..." info message (#6022)
The "Cannot establish guaranteed end-to-end encryption with ..." info
message can have lots of causes, and it happened twice to us now that it
took us some time to figure out which one it is.

So, include some more detail in the info message by simply adding the
non-translated error message in parantheses.

If we want to put in some more effort for nicer error messages, we
could:
- Introduce one new translated string "Cannot establish guaranteed
end-to-end encryption with …. Cause: %2$s" or similar (and remove the
old stock string)
- And/Or: Introduce new translated strings for all the possible errors
- And/Or: Maybe reword it in order to account better for the case that
the chat already is marked as g-e2ee, or use a different wording
(because if the chat is marked as g-e2ee then it might be nice to notify
the user that something may have gone wrong, but it's still working,
just that maybe the other side doesn't have us verified now)


![Screenshot_20241003-222245](https://github.com/user-attachments/assets/c064c82e-01ac-4bac-ab11-3c9ac9db5298)
2024-10-04 13:51:06 +02:00
iequidoo
d6845bd5e9 feat: Use IMAP APPEND command to upload sync messages (#5845)
Why:
- With IMAP APPEND we can upload messages directly to the DeltaChat folder (for non-chatmail
  accounts).
- We can set the `\Seen` flag immediately so that if the user has other MUA, it doesn't alert about
  a new message if it's just a sync message (there were several such reports on the support
  forum). Though this also isn't useful for chatmail.
- We don't need SMTP envelope and overall remove some overhead on processing sync messages.
2024-09-20 17:07:45 -03:00
iequidoo
5a6efdff44 fix: Save QR code token regardless of whether the group exists (#5954)
Groups promotion to other devices and QR code tokens synchronisation are not synchronised processes,
so there are reasons why a QR code token may arrive earlier than the first group message:
- We are going to upload sync messages via IMAP while group messages are sent by SMTP.
- If sync messages go to the mvbox, they can be fetched earlier than group messages from Inbox.
2024-09-16 16:40:26 -03:00
iequidoo
845420cf17 test: Alice is (non-)bot on Bob's side after QR contact setup 2024-09-02 18:06:52 -03:00
link2xt
dd1c2e836b feat(securejoin): ignore invalid *-request-with-auth messages silently 2024-09-01 16:10:41 +00:00