From ded2f6afc01b8cf6807f37525dce3dfe463831f6 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Fri, 6 Mar 2026 23:28:24 +0100 Subject: [PATCH] feat: Add OMEMO trust status indicators to the titlebar 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? --- src/command/cmd_defs.c | 7 +++++- src/omemo/omemo.c | 47 ++++++++++++++++++++++++++++++++++ src/omemo/omemo.h | 1 + src/ui/titlebar.c | 57 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 1 deletion(-) diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 3238bf15..d216dd16 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -2332,13 +2332,18 @@ static const struct cmd_t command_defs[] = { "/omemo clear_device_list", "/omemo qrcode") CMD_DESC( - "OMEMO commands to manage keys, and perform encryption during chat sessions.") + "OMEMO commands to manage keys, and perform encryption during chat sessions.\n" + "The title bar will show the OMEMO session status:\n" + "[OMEMO][trusted] - All active devices for the contact are trusted.\n" + "[OMEMO][untrusted] - One or more active devices for the contact are untrusted.\n") CMD_ARGS( { "gen", "Generate OMEMO cryptographic materials for current account." }, { "start []", "Start an OMEMO session with contact, or current recipient if omitted." }, { "end", "End the current OMEMO session." }, { "log on|off", "Enable or disable plaintext logging of OMEMO encrypted messages." }, { "log redact", "Log OMEMO encrypted messages, but replace the contents with [redacted]." }, + { "trust [] ", "Trust a fingerprint for a contact, or current recipient if omitted. If all active devices are trusted, the title bar will show [trusted]. Otherwise, it will show [untrusted]." }, + { "untrust [] ","Untrust a fingerprint for a contact, or current recipient if omitted." }, { "fingerprint []", "Show contact's fingerprints, or current recipient's if omitted." }, { "char ", "Set the character to be displayed next to OMEMO encrypted messages." }, { "trustmode manual", "Set the global OMEMO trust mode to manual, OMEMO keys has to be trusted manually." }, diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index f7841323..a28b7340 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -1155,6 +1155,53 @@ omemo_is_trusted_identity(const char* const jid, const char* const fingerprint) return trusted; } +gboolean +omemo_is_jid_trusted(const char* const jid) +{ + if (!omemo_loaded()) { + return FALSE; + } + + GList* device_list = g_hash_table_lookup(omemo_ctx.device_list, jid); + if (!device_list) { + return FALSE; + } + + GList* device_id_iter; + for (device_id_iter = device_list; device_id_iter != NULL; device_id_iter = device_id_iter->next) { + uint32_t device_id = GPOINTER_TO_INT(device_id_iter->data); + if (device_id == omemo_ctx.device_id && equals_our_barejid(jid)) { + continue; + } + + GHashTable* known_identities = g_hash_table_lookup(omemo_ctx.known_devices, jid); + if (!known_identities) { + return FALSE; + } + + gboolean found = FALSE; + GList* fp_list = g_hash_table_get_keys(known_identities); + GList* fp_iter; + for (fp_iter = fp_list; fp_iter != NULL; fp_iter = fp_iter->next) { + if (device_id == GPOINTER_TO_INT(g_hash_table_lookup(known_identities, fp_iter->data))) { + if (!omemo_is_trusted_identity(jid, fp_iter->data)) { + g_list_free(fp_list); + return FALSE; + } + found = TRUE; + break; + } + } + g_list_free(fp_list); + + if (!found) { + return FALSE; + } + } + + return TRUE; +} + static char* _omemo_fingerprint(ec_public_key* identity, gboolean formatted) { diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h index 39479da5..06708617 100644 --- a/src/omemo/omemo.h +++ b/src/omemo/omemo.h @@ -85,6 +85,7 @@ void omemo_trust(const char* const jid, const char* const fingerprint); void omemo_untrust(const char* const jid, const char* const fingerprint); GList* omemo_known_device_identities(const char* const jid); gboolean omemo_is_trusted_identity(const char* const jid, const char* const fingerprint); +gboolean omemo_is_jid_trusted(const char* const jid); char* omemo_fingerprint_autocomplete(const char* const search_str, gboolean previous, void* context); void omemo_fingerprint_autocomplete_reset(void); gboolean omemo_automatic_start(const char* const recipient); diff --git a/src/ui/titlebar.c b/src/ui/titlebar.c index 4c812e80..b18d0b6f 100644 --- a/src/ui/titlebar.c +++ b/src/ui/titlebar.c @@ -49,6 +49,9 @@ #include "ui/window_list.h" #include "ui/window.h" #include "ui/screen.h" +#ifdef HAVE_OMEMO +#include "omemo/omemo.h" +#endif #include "xmpp/roster_list.h" #include "xmpp/chat_session.h" @@ -412,6 +415,8 @@ _show_muc_privacy(ProfMucWin* mucwin) int encrypted_attrs = theme_attrs(THEME_TITLE_ENCRYPTED); if (mucwin->is_omemo) { + int untrusted_attrs = theme_attrs(THEME_TITLE_UNTRUSTED); + int trusted_attrs = theme_attrs(THEME_TITLE_TRUSTED); wprintw(win, " "); wattron(win, bracket_attrs); wprintw(win, "["); @@ -423,6 +428,32 @@ _show_muc_privacy(ProfMucWin* mucwin) wprintw(win, "]"); wattroff(win, bracket_attrs); +#ifdef HAVE_OMEMO + if (omemo_is_jid_trusted(mucwin->roomjid)) { + wprintw(win, " "); + wattron(win, bracket_attrs); + wprintw(win, "["); + wattroff(win, bracket_attrs); + wattron(win, trusted_attrs); + wprintw(win, "trusted"); + wattroff(win, trusted_attrs); + wattron(win, bracket_attrs); + wprintw(win, "]"); + wattroff(win, bracket_attrs); + } else { + wprintw(win, " "); + wattron(win, bracket_attrs); + wprintw(win, "["); + wattroff(win, bracket_attrs); + wattron(win, untrusted_attrs); + wprintw(win, "untrusted"); + wattroff(win, untrusted_attrs); + wattron(win, bracket_attrs); + wprintw(win, "]"); + wattroff(win, bracket_attrs); + } +#endif + return; } @@ -552,6 +583,32 @@ _show_privacy(ProfChatWin* chatwin) wprintw(win, "]"); wattroff(win, bracket_attrs); +#ifdef HAVE_OMEMO + if (omemo_is_jid_trusted(chatwin->barejid)) { + wprintw(win, " "); + wattron(win, bracket_attrs); + wprintw(win, "["); + wattroff(win, bracket_attrs); + wattron(win, trusted_attrs); + wprintw(win, "trusted"); + wattroff(win, trusted_attrs); + wattron(win, bracket_attrs); + wprintw(win, "]"); + wattroff(win, bracket_attrs); + } else { + wprintw(win, " "); + wattron(win, bracket_attrs); + wprintw(win, "["); + wattroff(win, bracket_attrs); + wattron(win, untrusted_attrs); + wprintw(win, "untrusted"); + wattroff(win, untrusted_attrs); + wattron(win, bracket_attrs); + wprintw(win, "]"); + wattroff(win, bracket_attrs); + } +#endif + return; }