Skip to content

Improve OMEMO UX#2104

Merged
jubalh merged 8 commits intomasterfrom
omemo-ux
Mar 9, 2026
Merged

Improve OMEMO UX#2104
jubalh merged 8 commits intomasterfrom
omemo-ux

Conversation

@jubalh
Copy link
Member

@jubalh jubalh commented Mar 6, 2026

Hopefully this enhanced the user experience for OMEMO users.

@jubalh jubalh added this to the next milestone Mar 6, 2026
@jubalh
Copy link
Member Author

jubalh commented Mar 6, 2026

@mdosch @StefanKropp can you review and test if this improves the OMEMO UX?

jubalh added 7 commits March 9, 2026 07:49
Previously the titlebar only showed [OMEMO], regardless of whether the
active session contained untrusted devices. This forced users to manually
run /omemo fingerprint to check the security status of their conversation,
making it difficult to know at a glance if a session was truly secure.

New function `omemo_is_jid_trusted()` to check if all active devices for a JID are trusted.
Update chat and MUC titlebar to display [trusted] or [untrusted] tags when an OMEMO session is active.
Not sure if MUC makes sense here?
Previously, Profanity silently updated OMEMO device lists and identity
caches in the background. This often led to confusion when a contact
added a new device, as encryption or decryption would eventually fail
due to untrusted keys without any prior warning to the user.

The `notifying` flag will distinguish between initial data loading and
realtime discovery.

We now print a message both when a contact publishes a new device ID or
when a new fingerprint is discovered.
When OMEMO encryption failed due to untrusted devices, the
user was presented with a generic error message. This made it difficult
to identify which specific fingerprints were causing the issue, forcing
users to manually hunt for untrusted keys using /omemo fingerprint.

New function `omemo_get_jid_untrusted_fingerprints` to specifically
identify unverified identities for a contact.
`omemo_on_message_send` will now catch encryption failures and
explicitly list the untrusted fingerprints in the chat window.
The /omemo fingerprint command provided a list of all keys ever
seen for a contact but did not indicate which keys were currently "active"
(present in the latest server device list). This made it difficult for users
to identify which fingerprints actually required verification to fix
encryption issues.

Users can now easily distinguish between devices currently in use and
historical keys that no longer matter.

When encryption fails users can immediately see which "active" key is
"untrusted," allowing them to verify the correct fingerprint fast.

Function `omemo_is_device_active` will check if a fingerprint belongs
to a device currently announced by the contacts server.
After typing `/omemo start` a user was not informed of what exactly
happens.
Profanity is fetching the device list and the key bundle for each
device. This happens asynchronously. It could be that it takes some time
and the user already starts typing a message, believing OMEMO is
working.

Now we print:
* Initiating OMEMO session..
* Fetching device list and key bundles
* OMEMO session ready

So the user understands much better the current situation.
…ures

If an incoming OMEMO message failed to decrypt (due to missing session
keys or untrusted identities), Profanity would fall back to displaying
the raw XMPP body. This usually contained a generic string like "This
message is encrypted with OMEMO,".

We wrote the detailed reason in the debug logs but the user only saw the
fallback message and probably wondered *why* the message wasn't
displayed properly.

I'm unsure if we should display the fallback message as well though.
@jubalh
Copy link
Member Author

jubalh commented Mar 9, 2026

Got this review by @sjaeckel:

This is no library, so we don't have to expect users to do weird things.

How about checking once at the beginning whether `error == NULL` and then error out, so we can set it unconditionally in the rest of the code?

Also there's a compiler hint `attribute(nonnull...)` that you could add to the declaration of the API using this pattern.

This applies to all instances where those enhanced errors are added.

@jubalh jubalh requested a review from sjaeckel March 9, 2026 07:16
@jubalh
Copy link
Member Author

jubalh commented Mar 9, 2026

When googling attribute(nonnull...) I found the GLIB G_GNUC_NONNULL and used that.

@sjaeckel
Copy link
Member

sjaeckel commented Mar 9, 2026

Looks better, thanks!

@jubalh jubalh force-pushed the omemo-ux branch 2 times, most recently from 42db5b4 to f79b1b1 Compare March 9, 2026 07:38
Add __attribute__((nonnull) hints to omemo_receive_message and
omemo_on_message_recv declarations to catch NULL arguments at
compiletime.
So we can set the error state unconditionally in the functions.
@jubalh
Copy link
Member Author

jubalh commented Mar 9, 2026

Lets use attribute(nonnull and not G_GNUC_NONNULL (for now). The latter needs more setup and we use more __attribute in other places.

@jubalh jubalh merged commit a26cdf3 into master Mar 9, 2026
7 checks passed
@jubalh jubalh deleted the omemo-ux branch March 9, 2026 08:15
jubalh added a commit that referenced this pull request Mar 9, 2026
a26cdf3 / #2104 added OMEMO trust status to the
title bar, but it was being re-calculated on UI refresh.

Update only on certain operations (like `/omemo trust`, new device
discoveries and even incoming OMEMO messages for example).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants