Commit Graph

76 Commits

Author SHA1 Message Date
Hocuri
d446a16fc6 Sync broadcast subscribers list (#7578)
fix #7497
2026-01-13 15:04:51 +01: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
iequidoo
98944efdb8 api: Forwarding messages to another profile (#7491)
Add `chat::forward_msgs_2ctx()` which takes another context as a parameter and forwards messages to
it and its jsonrpc wrapper `CommandApi::forward_messages_to_account()`.
2025-12-09 03:54:54 -03:00
Hocuri
531e0bc914 refactor!: Remove some unneeded stock strings (#7496)
There are quite some unneeded stock strings; this PR removes some of
them. None of these stock strings were actually set by the UI, or even
have translations in Transifex.
- We don't have AEAP anymore.
- The "I added/removed member" and "I left the group" strings are
anyways not meant to be shown to the user. Also, starting to translate
them now would leak the device language.

BREAKING CHANGE: This can theoretically be a breaking change because a
UI could reference one of the removed stock strings, so I marked it as
breaking just in case.
2025-11-24 19:55:12 +01:00
link2xt
3637fe67a7 feat: Hide To header in encrypted messages 2025-11-24 02:33:56 -03: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
1dbcd7f1f4 test: HP-Outer headers are added to messages with standard Header Protection (#7130) 2025-11-14 19:45:32 -03:00
link2xt
5f174ceaf2 test: test editing saved messages 2025-11-06 18:38:11 +00:00
link2xt
06b038ab5d fix: is_encrypted() should be true for Saved Messages chat
Otherwise UIs don't allow to edit messages sent to self.
This was likely broken in b417ba86bc
2025-11-06 18:38:11 +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
link2xt
2ada3cd613 fix: stop using leftgrps table 2025-10-28 19:41:47 +00:00
iequidoo
fc81cef113 refactor: Rename chat::create_group_chat() to create_group()
If we use modules (which are actually namespaces), we can use shorter names. Another approach is to
only use modules for internal code incapsulation and use full names like deltachat-ffi does.
2025-10-20 04:19:22 -03:00
iequidoo
04c2585c27 feat: Synchronize encrypted groups creation across devices (#7001)
Unencrypted groups don't have grpid since key-contacts were merged, so we don't sync them for now.
2025-10-20 04:19:22 -03:00
Simon Laux
59fac54f7b test: Add unique offsets to ids generated by TestContext to increase test correctness (#7297)
and fix the mistakes in tests that get discovered by this.

closes #6799
2025-10-19 17:08:23 +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
87035ff744 feat: slightly increase saturation of colors
It really depends on the screen,
but on Android phones with higher DPI
than laptop screen the contrast
looks a bit too low.

It should not be increased too high
because of clipping.
2025-10-09 20:28:21 +00:00
link2xt
23bfa4fc43 api!: remove APIs for video chat invitations 2025-10-05 12:19:10 +00:00
Hocuri
9ec0332483 feat: Add strings 'You left the channel.' and 'Scan to join Channel' (#7266)
Close https://github.com/chatmail/core/issues/7233

Part of https://github.com/chatmail/core/issues/6884
2025-10-02 14:57:24 +00:00
iequidoo
42b4b83f8e fix: Don't add "member removed" messages from nonmembers (#7207)
Such messages are actually ignored. Showing them to users creates confusion.
`ChatGroupMemberAdded` branch is modified for code consistency.
2025-09-23 05:57:57 -03:00
iequidoo
b9ff40c6b5 test: Message is OutFailed if all keys are missing (#6849)
Follow-up to 143ba6d5e7 before which a message remained in
`OutPending` indefinitely in such a case.
2025-09-09 09:48:12 -03:00
link2xt
66c9982822 fix: add "Messages are end-to-end encrypted." to non-protected groups
The messages are end-to-end encrypted
in encrypted group regardless
of whether the group is protected or not.
2025-09-02 18:29:53 +00:00
link2xt
aaa83a8f52 feat: replace HSLuv colors with OKLCh 2025-08-26 21:14:08 +00:00
iequidoo
d0cb2110e6 feat: Chat::get_color(): Use grpid, if present, instead of name
While testing the previous commit i understood that it's better to try giving different colors to
groups, particularly if their names are equal so that they visually differ, and at the same time
preserve the color if the group is renamed. Using `grpid` solves this. So let groups change colors
once and forever.
2025-08-24 12:10:54 -03:00
iequidoo
11e3480fe8 feat: create_group_ex(): Log and replace invalid chat name with "…"
We can't just fail on an invalid chat name because the user would lose the work already done in the
UI like selecting members. Sometimes happens to me when i put space into name.
2025-08-24 12:10:54 -03:00
link2xt
5476f69179 fix: don't break long group names with non-ASCII characters
The fix is in mail-builder 0.4.4.
2025-08-12 23:50:58 +00:00
link2xt
80af012962 fix: set correct sent_timestamp for saved outgoing messages 2025-08-07 07:58:53 +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
752f45f0f0 test: Unencrypted group creation (#6927) 2025-07-13 12:59:33 -03:00
Hocuri
6406f305b8 feat: Make it possible to leave broadcast channels (#6984)
Part of #6884.
The channel owner will not be notified in any way that you left, they
will only see that there is one member less.

For the translated stock strings, this is what we agreed on in the
group:
- Add a new "Leave Channel" stock string (will need to be done in UIs)
- Reword the existing "Are you sure you want to leave this group?"
string to "Are you sure you want to leave?" (the options are "Cancel"
and "Leave Group" / "Leave Channel", so it's clear what you are leaving)
(will need to be done in the deltachat-android repo, other UIs will pick
it up automatically)
- Reword the existing "You left the group." string to "You left". (done
here, I will adapt the strings in deltachat-android, too)

I adapted DC Android by pushing
6df2740884
to https://github.com/deltachat/deltachat-android/pull/3783.

---------

Co-authored-by: l <link2xt@testrun.org>
2025-07-11 12:34:05 +00:00
iequidoo
3f66ae91cd feat: Check images passed as File before making them Image
We don't want images having unsupported format or corrupted ones to be sent as `Image` and appear in
the "Images" tab in UIs because they can't be displayed correctly.
2025-07-08 17:43:13 -03:00
iequidoo
75b7bea78f fix: Decide on filename used for sending depending on the original Viewtype
If a user attaches an image as `File`, we should send the original filename. And vice versa, if it's
`Image` originally, we mustn't reveal the filename.

The filename used for sending is now also saved to the db, so all the sender's devices will display
the same filename in the message info.
2025-07-08 17:43:13 -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
Hocuri
aad8f698dd fix: Don't send ChatGroupId for broadcast channels (#6975)
Older versions of Delta Chat ignore the message if it contains a
ChatGroupId header. ("older versions" means all versions without #6901,
i.e.currently released versions)

This means that without this PR, broadcast channel messages sent from
current main don't arrive at a device running latest released DC.

Part of #6884.
2025-07-07 12:06:54 +02:00
Hocuri
0a73c2b7ab feat: Show broadcast channels in their own, proper "Channel" chat (#6901)
Part of #6884 

----

- [x] Add new chat type `InBroadcastChannel` and `OutBroadcastChannel`
for incoming / outgoing channels, where the former is similar to a
`Mailinglist` and the latter is similar to a `Broadcast` (which is
removed)
- Consideration for naming: `InChannel`/`OutChannel` (without
"broadcast") would be shorter, but less greppable because we already
have a lot of occurences of `channel` in the code. Consistently calling
them `BcChannel`/`bc_channel` in the code would be both short and
greppable, but a bit arcane when reading it at first. Opinions are
welcome; if I hear none, I'll keep with `BroadcastChannel`.
- [x] api: Add create_broadcast_channel(), deprecate
create_broadcast_list() (or `create_channel()` / `create_bc_channel()`
if we decide to switch)
  - Adjust code comments to match the new behavior.
- [x] Ask Desktop developers what they use `is_broadcast` field for, and
whether it should be true for both outgoing & incoming channels (or look
it up myself)
- I added `is_out_broadcast_channel`, and deprecated `is_broadcast`, for
now
- [x] When the user changes the broadcast channel name, immediately show
this change on receiving devices
- [x] Allow to change brodacast channel avatar, and immediately apply it
on the receiving device
- [x] Make it possible to block InBroadcastChannel
- [x] Make it possible to set the avatar of an OutgoingChannel, and
apply it on the receiving side
- [x] DECIDE whether we still want to use the broadcast icon as the
default icon or whether we want to use the letter-in-a-circle
- We decided to use the letter-in-a-circle for now, because it's easier
to implement, and I need to stay in the time plan
- [x] chat.rs: Return an error if the user tries to modify a
`InBroadcastChannel`
- [x] Add automated regression tests
- [x] Grep for `broadcast` and see whether there is any other work I
need to do
- [x] Bug: Don't show `~` in front of the sender's same in broadcast
lists

----

Note that I removed the following guard:

```rust
        if !new_chat_contacts.contains(&ContactId::SELF) {
            warn!(
                context,
                "Received group avatar update for group chat {} we are not a member of.", chat.id
            );
        } else if !new_chat_contacts.contains(&from_id) {
            warn!(
                context,
                "Contact {from_id} attempts to modify group chat {} avatar without being a member.",
                chat.id,
            );
        } else [...]
```

i.e. with this change, non-members will be able to modify the avatar.
Things were slightly easier this way, and I think that this is in line
with non-members being able to modify the group name and memberlist
(they need to know the Group-Chat-Id, anyway), but I can also change it
back.
2025-07-02 20:40:30 +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
iequidoo
ce04e904e2 fix: Sort multiple saved messages by timestamp (#6862) 2025-06-06 03:59:36 -03:00
bjoern
a24e6d4278 feat: sort apps by recently-updated (#6875)
closes #6873 , see there for reasoning.

tested that on iOS already, works like a charm - and was much easier
than expected as @iequidoo already updated `timestamp_rcvd` on status
updates in https://github.com/chatmail/core/pull/5388

~~a test is missing, ordering is not tested at all, will check if that
is doable reasonably easy~~ EDIT: added a test
2025-05-26 18:33:48 +02:00
link2xt
09d18f9097 test: fixup for test_restore_backup_after_60_days 2025-05-15 18:02:19 +00:00
Sebastian Klähn
846c8e7f1b Generate rfc724_mid when creating Message (#6704)
Set `rfc724_mid` in `Message::new()`, `Message::new_text()`, and
`Message::default()` instead of when sending the message. This way the
rfc724 mid can be read in the draft stage which makes it more consistent
for bots. Tests had to be adjusted to create multiple messages to get
unique mid, otherwise core would not send the messages out.
2025-05-05 15:06:05 +00:00
iequidoo
98a1b9e373 test: Profile data is attached to group leave messages 2025-05-05 05:28:43 -03:00
link2xt
1ea8647018 test: test that key of the recipient is gossiped in 1:1 chats
It is needed for multi-device setups.
2025-04-16 12:00:47 +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
iequidoo
9229eae4e0 test: Autocrypt-Gossip header isn't sent in broadcast messages
Follow-up to 175145969c.
2025-04-11 00:39:32 -03:00
B. Petersen
3b35d5e0ea fix: encrypt broadcast lists
it was all the time questionable if not encrypting broadcast lists
rules the issue that recipients may know each other cryptographically.

however, meanwhile with chatmail, unncrypted broadcasts are no longer possible,
and we actively broke workflows eg. from this teacher:
https://support.delta.chat/t/broadcast-funktioniert-nach-update-nicht-meht/3694

this basically reverts commit
7e5907daf2
which was that time added last-minute and without lots discussions :)

let the students get their homework again :)
2025-04-07 20:07:05 +02:00
link2xt
c8c6beb1b6 test: port test_forward_encrypted_to_unencrypted from legacy Python to Rust 2025-04-06 07:42:34 +00:00
iequidoo
a1837aeb8c feat: Clear Param::IsEdited when forwarding a message 2025-04-01 15:07:51 -03:00
link2xt
ddc2f55a6f test: encrypt 15 more Rust tests
- chat::chat_tests::test_forward_group
- chat::chat_tests::test_resend_foreign_message_fails
- chat::chat_tests::test_resend_info_message_fails
- ephemeral::ephemeral_tests::test_ephemeral_timer_non_member
- receive_imf::receive_imf_tests::test_delayed_removal_is_ignored
- receive_imf::receive_imf_tests::test_dont_readd_with_normal_msg
- receive_imf::receive_imf_tests::test_dont_recreate_contacts_on_add_remove
- receive_imf::receive_imf_tests::test_member_left_does_not_create_chat
- receive_imf::receive_imf_tests::test_outgoing_private_reply_multidevice
- receive_imf::receive_imf_tests::test_recreate_member_list_on_missing_add_of_self
- receive_imf::receive_imf_tests::test_references
- receive_imf::receive_imf_tests::test_send_as_bot
- receive_imf::receive_imf_tests::test_unsigned_chat_group_hdr
- securejoin::securejoin_tests::test_unknown_sender
- webxdc::webxdc_tests::test_webxdc_reject_updates_from_non_groupmembers
2025-04-01 01:09:55 +00:00
bjoern
97b0d09ed2 feat: get contact-id for info messages (#6714)
instead of showing addresses in info message, provide an API to get the
contact-id.

UI can then make the info message tappable and open the contact profile
in scope

the corresponding iOS PR - incl. **screencast** - is at
https://github.com/deltachat/deltachat-ios/pull/2652 ; jsonrpc can come
in a subsequent PR when things are settled on android/ios

the number of parameters in `add_info_msg_with_cmd` gets bigger and
bigger, however, i did not want to refactor this in this PR. it is also
not really adding complexity



closes #6702

---------

Co-authored-by: link2xt <link2xt@testrun.org>
Co-authored-by: Hocuri <hocuri@gmx.de>
2025-03-31 18:56:57 +02:00