From ded2f6afc01b8cf6807f37525dce3dfe463831f6 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Fri, 6 Mar 2026 23:28:24 +0100 Subject: [PATCH 1/8] 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; } From ce9b5140d5e6da31bd8c75874f840d28f06a7cd9 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Fri, 6 Mar 2026 23:40:51 +0100 Subject: [PATCH 2/8] feat: Notify users when new OMEMO devices or fingerprints are discovered 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. --- src/omemo/omemo.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index a28b7340..4b310649 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -105,6 +105,7 @@ typedef struct omemo_context prof_keyfile_t knowndevices; GHashTable* known_devices; gboolean loaded; + gboolean notifying; } omemo_context; static omemo_context omemo_ctx; @@ -168,6 +169,8 @@ _omemo_finalize_identity_load(ProfAccount* account) omemo_devicelist_subscribe(); + omemo_ctx.notifying = TRUE; + return TRUE; } @@ -254,6 +257,7 @@ omemo_on_connect(ProfAccount* account) signal_protocol_store_context_set_identity_key_store(omemo_ctx.store, &identity_key_store); omemo_ctx.loaded = FALSE; + omemo_ctx.notifying = FALSE; omemo_ctx.device_list = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)g_list_free); omemo_ctx.device_list_handler = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL); omemo_ctx.known_devices = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)g_hash_table_destroy); @@ -515,6 +519,40 @@ omemo_set_device_list(const char* const from, GList* device_list) log_debug("[OMEMO] Setting device list for %s", STR_MAYBE_NULL(from)); auto_jid Jid* jid = jid_create(from ?: connection_get_fulljid()); + if (omemo_ctx.notifying) { + GList* old_list = g_hash_table_lookup(omemo_ctx.device_list, jid->barejid); + GList* new_iter; + for (new_iter = device_list; new_iter != NULL; new_iter = new_iter->next) { + uint32_t dev_id = GPOINTER_TO_INT(new_iter->data); + gboolean found = FALSE; + GList* old_iter; + for (old_iter = old_list; old_iter != NULL; old_iter = old_iter->next) { + if (GPOINTER_TO_INT(old_iter->data) == dev_id) { + found = TRUE; + break; + } + } + + if (!found) { + if (equals_our_barejid(jid->barejid)) { + if (dev_id != omemo_ctx.device_id) { + cons_show("New OMEMO device (ID: %u) added to your account.", dev_id); + } + } else { + ProfChatWin* chatwin = wins_get_chat(jid->barejid); + if (chatwin) { + win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "New OMEMO device (ID: %u) found for %s.", dev_id, jid->barejid); + } else { + ProfMucWin* mucwin = wins_get_muc(jid->barejid); + if (mucwin) { + win_println((ProfWin*)mucwin, THEME_DEFAULT, "!", "New OMEMO device (ID: %u) found for %s.", dev_id, jid->barejid); + } + } + } + } + } + } + g_hash_table_insert(omemo_ctx.device_list, strdup(jid->barejid), device_list); OmemoDeviceListHandler handler = g_hash_table_lookup(omemo_ctx.device_list_handler, jid->barejid); @@ -1744,6 +1782,27 @@ _cache_device_identity(const char* const jid, uint32_t device_id, ec_public_key* if (!fingerprint) { return; } + + if (omemo_ctx.notifying) { + if (!g_hash_table_contains(known_identities, fingerprint)) { + char* formatted = omemo_format_fingerprint(fingerprint); + if (equals_our_barejid(jid)) { + cons_show("New OMEMO fingerprint for your account: %s (ID: %u).", formatted, device_id); + } else { + ProfChatWin* chatwin = wins_get_chat(jid); + if (chatwin) { + win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "New OMEMO fingerprint for %s: %s (ID: %u).", jid, formatted, device_id); + } else { + ProfMucWin* mucwin = wins_get_muc(jid); + if (mucwin) { + win_println((ProfWin*)mucwin, THEME_DEFAULT, "!", "New OMEMO fingerprint for %s: %s (ID: %u).", jid, formatted, device_id); + } + } + } + free(formatted); + } + } + log_debug("[OMEMO] cache identity for %s:%d: %s", jid, device_id, fingerprint); g_hash_table_insert(known_identities, strdup(fingerprint), GINT_TO_POINTER(device_id)); From 99c03f8c3b8d67632281804dd9dad15091f6999e Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Fri, 6 Mar 2026 23:50:25 +0100 Subject: [PATCH 3/8] feat: Provide detailed encryption failure messages for OMEMO 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. --- src/omemo/omemo.c | 81 ++++++++++++++++++++++++++++++++++++++++++++--- src/omemo/omemo.h | 1 + 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index 4b310649..568932c1 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -875,10 +875,42 @@ omemo_on_message_send(ProfWin* win, const char* const message, gboolean request_ // Don't send the message if no key could be encrypted. // (Since none of the recipients would be able to read the message.) if (keys == NULL) { - win_println(win, THEME_ERROR, "!", "This message cannot be decrypted for any recipient.\n" - "You should trust your recipients' device fingerprint(s) using \"/omemo trust FINGERPRINT\".\n" - "It could also be that the key bundle of the recipient(s) have not been received. " - "In this case, you could try \"omemo end\", \"omemo start\", and send the message again."); + win_println(win, THEME_ERROR, "!", "This message cannot be encrypted for any recipient."); + + // Check for untrusted fingerprints for each recipient + GList* recipients = NULL; + if (muc) { + ProfMucWin* mucwin = (ProfMucWin*)win; + GList* members = muc_members(mucwin->roomjid); + GList* iter; + for (iter = members; iter != NULL; iter = iter->next) { + auto_jid Jid* jidp = jid_create(iter->data); + recipients = g_list_append(recipients, strdup(jidp->barejid)); + } + g_list_free(members); + } else { + ProfChatWin* chatwin = (ProfChatWin*)win; + recipients = g_list_append(recipients, strdup(chatwin->barejid)); + } + + GList* rec_iter; + for (rec_iter = recipients; rec_iter != NULL; rec_iter = rec_iter->next) { + GList* untrusted = omemo_get_jid_untrusted_fingerprints(rec_iter->data); + if (untrusted) { + win_println(win, THEME_ERROR, "!", "Untrusted OMEMO fingerprints for %s:", (char*)rec_iter->data); + GList* fp_iter; + for (fp_iter = untrusted; fp_iter != NULL; fp_iter = fp_iter->next) { + char* formatted = omemo_format_fingerprint(fp_iter->data); + win_println(win, THEME_ERROR, "!", " - %s", formatted); + free(formatted); + } + win_println(win, THEME_ERROR, "!", "Use \"/omemo trust %s \" to trust them.", (char*)rec_iter->data); + g_list_free_full(untrusted, free); + } + } + g_list_free_full(recipients, free); + + win_println(win, THEME_ERROR, "!", "It could also be that key bundles have not been received. Try \"/omemo end\", then \"/omemo start\"."); goto out; } @@ -1240,6 +1272,47 @@ omemo_is_jid_trusted(const char* const jid) return TRUE; } +GList* +omemo_get_jid_untrusted_fingerprints(const char* const jid) +{ + if (!omemo_loaded()) { + return NULL; + } + + GList* device_list = g_hash_table_lookup(omemo_ctx.device_list, jid); + if (!device_list) { + return NULL; + } + + GList* untrusted_fps = NULL; + 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) { + continue; + } + + 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)) { + untrusted_fps = g_list_append(untrusted_fps, g_strdup(fp_iter->data)); + } + break; + } + } + g_list_free(fp_list); + } + + return untrusted_fps; +} + static char* _omemo_fingerprint(ec_public_key* identity, gboolean formatted) { diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h index 06708617..8618b6e7 100644 --- a/src/omemo/omemo.h +++ b/src/omemo/omemo.h @@ -86,6 +86,7 @@ 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); +GList* omemo_get_jid_untrusted_fingerprints(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); From 5a3083f273954ec395224d6670d87a865b1c7438 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Fri, 6 Mar 2026 23:57:44 +0100 Subject: [PATCH 4/8] feat: Show active and trust status in /omemo fingerprint 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. --- src/command/cmd_funcs.c | 3 ++- src/omemo/omemo.c | 33 ++++++++++++++++++++++++++++++ src/omemo/omemo.h | 1 + tests/unittests/omemo/stub_omemo.c | 18 ++++++++++++++++ 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 7f574aff..4d847778 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -8686,8 +8686,9 @@ cmd_omemo_fingerprint(ProfWin* window, const char* const command, gchar** args) for (GList* fingerprint = fingerprints; fingerprint != NULL; fingerprint = fingerprint->next) { auto_char char* formatted_fingerprint = omemo_format_fingerprint(fingerprint->data); gboolean trusted = omemo_is_trusted_identity(jid->barejid, fingerprint->data); + gboolean active = omemo_is_device_active(jid->barejid, fingerprint->data); - win_println(window, THEME_DEFAULT, "-", "%s's OMEMO fingerprint: %s%s", jid->barejid, formatted_fingerprint, trusted ? " (trusted)" : ""); + win_println(window, THEME_DEFAULT, "-", "%s's OMEMO fingerprint: %s%s%s", jid->barejid, formatted_fingerprint, trusted ? " (trusted)" : " (untrusted)", active ? " (active)" : " (inactive)"); } g_list_free(fingerprints); diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index 568932c1..e6d3a6ce 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -1313,6 +1313,39 @@ omemo_get_jid_untrusted_fingerprints(const char* const jid) return untrusted_fps; } +gboolean +omemo_is_device_active(const char* const jid, const char* const fingerprint) +{ + if (!omemo_loaded()) { + return FALSE; + } + + GList* device_list = g_hash_table_lookup(omemo_ctx.device_list, jid); + if (!device_list) { + return FALSE; + } + + GHashTable* known_identities = g_hash_table_lookup(omemo_ctx.known_devices, jid); + if (!known_identities) { + return FALSE; + } + + void* device_id = g_hash_table_lookup(known_identities, fingerprint); + if (!device_id) { + return FALSE; + } + + uint32_t dev_id = GPOINTER_TO_INT(device_id); + GList* iter; + for (iter = device_list; iter != NULL; iter = iter->next) { + if (GPOINTER_TO_INT(iter->data) == dev_id) { + return TRUE; + } + } + + return FALSE; +} + static char* _omemo_fingerprint(ec_public_key* identity, gboolean formatted) { diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h index 8618b6e7..47ebaaf7 100644 --- a/src/omemo/omemo.h +++ b/src/omemo/omemo.h @@ -87,6 +87,7 @@ 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); GList* omemo_get_jid_untrusted_fingerprints(const char* const jid); +gboolean omemo_is_device_active(const char* const jid, const char* const fingerprint); 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/tests/unittests/omemo/stub_omemo.c b/tests/unittests/omemo/stub_omemo.c index a19c6b71..c445eb23 100644 --- a/tests/unittests/omemo/stub_omemo.c +++ b/tests/unittests/omemo/stub_omemo.c @@ -42,12 +42,30 @@ omemo_is_trusted_identity(const char* const jid, const char* const fingerprint) return TRUE; } +gboolean +omemo_is_jid_trusted(const char* const jid) +{ + return TRUE; +} + +GList* +omemo_get_jid_untrusted_fingerprints(const char* const jid) +{ + return NULL; +} + GList* omemo_known_device_identities(const char* const jid) { return NULL; } +gboolean +omemo_is_device_active(const char* const jid, const char* const fingerprint) +{ + return TRUE; +} + gboolean omemo_loaded(void) { From b20e3f1a0c3c89f2b1140b24d5cee01ebac07fc0 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Sat, 7 Mar 2026 00:10:33 +0100 Subject: [PATCH 5/8] feat: Improve feedback during OMEMO session Initiation 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. --- src/command/cmd_funcs.c | 2 ++ src/omemo/omemo.c | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 4d847778..326e3e62 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -8479,6 +8479,7 @@ cmd_omemo_start(ProfWin* window, const char* const command, gchar** args) } accounts_add_omemo_state(session_get_account_name(), chatwin->barejid, TRUE); + win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "Initiating OMEMO session with %s...", chatwin->barejid); omemo_start_session(chatwin->barejid); chatwin->is_omemo = TRUE; } else if (window->type == WIN_MUC) { @@ -8493,6 +8494,7 @@ cmd_omemo_start(ProfWin* window, const char* const command, gchar** args) if (muc_anonymity_type(mucwin->roomjid) == MUC_ANONYMITY_TYPE_NONANONYMOUS && muc_member_type(mucwin->roomjid) == MUC_MEMBER_TYPE_MEMBERS_ONLY) { accounts_add_omemo_state(session_get_account_name(), mucwin->roomjid, TRUE); + win_println((ProfWin*)mucwin, THEME_DEFAULT, "!", "Initiating OMEMO session in %s...", mucwin->roomjid); omemo_start_muc_sessions(mucwin->roomjid); mucwin->is_omemo = TRUE; } else { diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index e6d3a6ce..2fe05234 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -729,8 +729,30 @@ omemo_start_device_session(const char* const jid, uint32_t device_id, } log_debug("[OMEMO] create session with %s device %d", jid, device_id); + if (omemo_ctx.notifying) { + ProfChatWin* chatwin = wins_get_chat(jid); + if (chatwin) { + win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "OMEMO session with %s (device %u) ready.", jid, device_id); + } else { + ProfMucWin* mucwin = wins_get_muc(jid); + if (mucwin) { + win_println((ProfWin*)mucwin, THEME_DEFAULT, "!", "OMEMO session with %s (device %u) ready.", jid, device_id); + } + } + } } else { log_debug("[OMEMO] session with %s device %d exists", jid, device_id); + if (omemo_ctx.notifying) { + ProfChatWin* chatwin = wins_get_chat(jid); + if (chatwin) { + win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "OMEMO session with %s (device %u) already exists.", jid, device_id); + } else { + ProfMucWin* mucwin = wins_get_muc(jid); + if (mucwin) { + win_println((ProfWin*)mucwin, THEME_DEFAULT, "!", "OMEMO session with %s (device %u) already exists.", jid, device_id); + } + } + } } out: From 4d49c2b7463f91a13695a957b498afb760404475 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Sat, 7 Mar 2026 00:31:44 +0100 Subject: [PATCH 6/8] feat: Provide descriptive fallback messages for OMEMO decryption failures 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. --- src/omemo/omemo.c | 34 ++++++++++++- src/omemo/omemo.h | 3 +- src/xmpp/message.c | 76 +++++++++++++++++++++++++++--- src/xmpp/omemo.c | 32 ++++++++++++- src/xmpp/omemo.h | 3 +- src/xmpp/xmpp.h | 12 +++++ tests/unittests/omemo/stub_omemo.c | 21 +++++++++ 7 files changed, 169 insertions(+), 12 deletions(-) diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index 2fe05234..98aa8af6 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -1014,13 +1014,21 @@ out: char* omemo_on_message_recv(const char* const from_jid, uint32_t sid, const unsigned char* const iv, size_t iv_len, GList* keys, - const unsigned char* const payload, size_t payload_len, gboolean muc, gboolean* trusted) + const unsigned char* const payload, size_t payload_len, gboolean muc, gboolean* trusted, omemo_error_t* error) { unsigned char* plaintext = NULL; auto_jid Jid* sender = NULL; auto_jid Jid* from = jid_create(from_jid); + + if (error) { + *error = OMEMO_ERR_NONE; + } + if (!from) { log_error("[OMEMO][RECV] Invalid jid %s", from_jid); + if (error) { + *error = OMEMO_ERR_INVALID_JID; + } return NULL; } @@ -1036,6 +1044,9 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid, if (!key) { log_warning("[OMEMO][RECV] received a message with no corresponding key"); + if (error) { + *error = OMEMO_ERR_NO_KEY; + } return NULL; } @@ -1052,6 +1063,9 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid, g_list_free(roster); if (!sender) { log_warning("[OMEMO][RECV] cannot find MUC message sender fulljid"); + if (error) { + *error = OMEMO_ERR_MUC_SENDER_NOT_FOUND; + } return NULL; } } else { @@ -1069,6 +1083,9 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid, res = session_cipher_create(&cipher, omemo_ctx.store, &address, omemo_ctx.signal); if (res != 0) { log_error("[OMEMO][RECV] cannot create session cipher"); + if (error) { + *error = OMEMO_ERR_NO_SESSION; + } return NULL; } @@ -1127,13 +1144,23 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid, session_cipher_free(cipher); if (res != 0) { - log_error("[OMEMO][RECV] cannot decrypt message key"); + log_error("[OMEMO][RECV] cannot decrypt message key: %d", res); + if (error) { + if (!*trusted) { + *error = OMEMO_ERR_NOT_TRUSTED; + } else { + *error = OMEMO_ERR_DECRYPT_FAILED; + } + } return NULL; } if (signal_buffer_len(plaintext_key) != AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH) { log_error("[OMEMO][RECV] invalid key length"); signal_buffer_free(plaintext_key); + if (error) { + *error = OMEMO_ERR_DECRYPT_FAILED; + } return NULL; } @@ -1146,6 +1173,9 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid, if (res != 0) { log_error("[OMEMO][RECV] cannot decrypt message: %s", gcry_strerror(res)); free(plaintext); + if (error) { + *error = OMEMO_ERR_DECRYPT_FAILED; + } return NULL; } diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h index 47ebaaf7..62d28197 100644 --- a/src/omemo/omemo.h +++ b/src/omemo/omemo.h @@ -98,8 +98,9 @@ void omemo_start_muc_sessions(const char* const roomjid); void omemo_start_device_session(const char* const jid, uint32_t device_id, GList* prekeys, uint32_t signed_prekey_id, const unsigned char* const signed_prekey, size_t signed_prekey_len, const unsigned char* const signature, size_t signature_len, const unsigned char* const identity_key, size_t identity_key_len); gboolean omemo_loaded(void); + char* omemo_on_message_send(ProfWin* win, const char* const message, gboolean request_receipt, gboolean muc, const char* const replace_id); -char* omemo_on_message_recv(const char* const from, uint32_t sid, const unsigned char* const iv, size_t iv_len, GList* keys, const unsigned char* const payload, size_t payload_len, gboolean muc, gboolean* trusted); +char* omemo_on_message_recv(const char* const from, uint32_t sid, const unsigned char* const iv, size_t iv_len, GList* keys, const unsigned char* const payload, size_t payload_len, gboolean muc, gboolean* trusted, omemo_error_t* error); char* omemo_encrypt_file(FILE* in, FILE* out, off_t file_size, int* gcry_res); gcry_error_t omemo_decrypt_file(FILE* in, FILE* out, off_t file_size, const char* fragment); diff --git a/src/xmpp/message.c b/src/xmpp/message.c index bc07b073..4562cc87 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -356,6 +356,7 @@ message_init(void) ProfMessage* message = g_new0(ProfMessage, 1); message->enc = PROF_MSG_ENC_NONE; + message->omemo_err = OMEMO_ERR_NONE; message->trusted = true; message->type = PROF_MSG_TYPE_UNINITIALIZED; @@ -1110,8 +1111,29 @@ _handle_groupchat(xmpp_stanza_t* const stanza) // check omemo encryption #ifdef HAVE_OMEMO - message->plain = omemo_receive_message(stanza, &message->trusted); - if (message->plain != NULL) { + message->plain = omemo_receive_message(stanza, &message->trusted, &message->omemo_err); + if (message->omemo_err != OMEMO_ERR_NONE) { + message->enc = PROF_MSG_ENC_OMEMO; + if (message->plain == NULL) { + switch (message->omemo_err) { + case OMEMO_ERR_NO_KEY: + message->plain = g_strdup("OMEMO message received but no key for this device found."); + break; + case OMEMO_ERR_NOT_TRUSTED: + message->plain = g_strdup("OMEMO message received but sender identity is untrusted."); + break; + case OMEMO_ERR_NO_SESSION: + message->plain = g_strdup("OMEMO message received but no session found. Try '/omemo start'."); + break; + case OMEMO_ERR_DECRYPT_FAILED: + message->plain = g_strdup("OMEMO message received but decryption failed."); + break; + default: + message->plain = g_strdup("OMEMO message received but could not be decrypted."); + break; + } + } + } else if (message->plain != NULL) { message->enc = PROF_MSG_ENC_OMEMO; } #endif @@ -1270,8 +1292,29 @@ _handle_muc_private_message(xmpp_stanza_t* const stanza) // check omemo encryption #ifdef HAVE_OMEMO - message->plain = omemo_receive_message(stanza, &message->trusted); - if (message->plain != NULL) { + message->plain = omemo_receive_message(stanza, &message->trusted, &message->omemo_err); + if (message->omemo_err != OMEMO_ERR_NONE) { + message->enc = PROF_MSG_ENC_OMEMO; + if (message->plain == NULL) { + switch (message->omemo_err) { + case OMEMO_ERR_NO_KEY: + message->plain = g_strdup("OMEMO message received but no key for this device found."); + break; + case OMEMO_ERR_NOT_TRUSTED: + message->plain = g_strdup("OMEMO message received but sender identity is untrusted."); + break; + case OMEMO_ERR_NO_SESSION: + message->plain = g_strdup("OMEMO message received but no session found. Try '/omemo start'."); + break; + case OMEMO_ERR_DECRYPT_FAILED: + message->plain = g_strdup("OMEMO message received but decryption failed."); + break; + default: + message->plain = g_strdup("OMEMO message received but could not be decrypted."); + break; + } + } + } else if (message->plain != NULL) { message->enc = PROF_MSG_ENC_OMEMO; } #endif @@ -1437,8 +1480,29 @@ _handle_chat(xmpp_stanza_t* const stanza, gboolean is_mam, gboolean is_carbon, c #ifdef HAVE_OMEMO // check omemo encryption - message->plain = omemo_receive_message(stanza, &message->trusted); - if (message->plain != NULL) { + message->plain = omemo_receive_message(stanza, &message->trusted, &message->omemo_err); + if (message->omemo_err != OMEMO_ERR_NONE) { + message->enc = PROF_MSG_ENC_OMEMO; + if (message->plain == NULL) { + switch (message->omemo_err) { + case OMEMO_ERR_NO_KEY: + message->plain = g_strdup("OMEMO message received but no key for this device found."); + break; + case OMEMO_ERR_NOT_TRUSTED: + message->plain = g_strdup("OMEMO message received but sender identity is untrusted."); + break; + case OMEMO_ERR_NO_SESSION: + message->plain = g_strdup("OMEMO message received but no session found. Try '/omemo start'."); + break; + case OMEMO_ERR_DECRYPT_FAILED: + message->plain = g_strdup("OMEMO message received but decryption failed."); + break; + default: + message->plain = g_strdup("OMEMO message received but could not be decrypted."); + break; + } + } + } else if (message->plain != NULL) { message->enc = PROF_MSG_ENC_OMEMO; } #endif diff --git a/src/xmpp/omemo.c b/src/xmpp/omemo.c index d41588a6..d53b83d7 100644 --- a/src/xmpp/omemo.c +++ b/src/xmpp/omemo.c @@ -350,7 +350,7 @@ out: } char* -omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted) +omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_error_t* error) { char* plaintext = NULL; const char* type = xmpp_stanza_get_type(stanza); @@ -360,6 +360,10 @@ omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted) char* iv_text = NULL; char* payload_text = NULL; + if (error) { + *error = OMEMO_ERR_NONE; + } + xmpp_stanza_t* encrypted = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_OMEMO); if (!encrypted) { return NULL; @@ -367,40 +371,64 @@ omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted) xmpp_stanza_t* header = xmpp_stanza_get_child_by_name(encrypted, "header"); if (!header) { + if (error) { + *error = OMEMO_ERR_OTHER; + } return NULL; } const char* sid_text = xmpp_stanza_get_attribute(header, "sid"); if (!sid_text) { + if (error) { + *error = OMEMO_ERR_OTHER; + } return NULL; } uint32_t sid = strtoul(sid_text, NULL, 10); xmpp_stanza_t* iv = xmpp_stanza_get_child_by_name(header, "iv"); if (!iv) { + if (error) { + *error = OMEMO_ERR_OTHER; + } return NULL; } iv_text = xmpp_stanza_get_text(iv); if (!iv_text) { + if (error) { + *error = OMEMO_ERR_OTHER; + } return NULL; } size_t iv_len; iv_raw = g_base64_decode(iv_text, &iv_len); if (!iv_raw) { + if (error) { + *error = OMEMO_ERR_OTHER; + } return NULL; } xmpp_stanza_t* payload = xmpp_stanza_get_child_by_name(encrypted, "payload"); if (!payload) { + if (error) { + *error = OMEMO_ERR_OTHER; + } goto quit; } payload_text = xmpp_stanza_get_text(payload); if (!payload_text) { + if (error) { + *error = OMEMO_ERR_OTHER; + } goto quit; } size_t payload_len; payload_raw = g_base64_decode(payload_text, &payload_len); if (!payload_raw) { + if (error) { + *error = OMEMO_ERR_OTHER; + } goto quit; } @@ -439,7 +467,7 @@ omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted) plaintext = omemo_on_message_recv(from, sid, iv_raw, iv_len, keys, payload_raw, payload_len, - g_strcmp0(type, STANZA_TYPE_GROUPCHAT) == 0, trusted); + g_strcmp0(type, STANZA_TYPE_GROUPCHAT) == 0, trusted, error); if (keys) { g_list_free_full(keys, (GDestroyNotify)omemo_key_free); diff --git a/src/xmpp/omemo.h b/src/xmpp/omemo.h index 9f29cb96..e26029e1 100644 --- a/src/xmpp/omemo.h +++ b/src/xmpp/omemo.h @@ -44,4 +44,5 @@ void omemo_devicelist_request(const char* const jid); void omemo_bundle_publish(gboolean first); void omemo_bundle_request(const char* const jid, uint32_t device_id, ProfIqCallback func, ProfIqFreeCallback free_func, void* userdata); int omemo_start_device_session_handle_bundle(xmpp_stanza_t* const stanza, void* const userdata); -char* omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted); + +char* omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_error_t* error); diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 5fd214c9..620fb66e 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -150,6 +150,17 @@ typedef enum { PROF_MSG_TYPE_MUCPM } prof_msg_type_t; +typedef enum { + OMEMO_ERR_NONE = 0, + OMEMO_ERR_NO_KEY, + OMEMO_ERR_NOT_TRUSTED, + OMEMO_ERR_NO_SESSION, + OMEMO_ERR_DECRYPT_FAILED, + OMEMO_ERR_INVALID_JID, + OMEMO_ERR_MUC_SENDER_NOT_FOUND, + OMEMO_ERR_OTHER +} omemo_error_t; + typedef struct prof_message_t { Jid* from_jid; @@ -172,6 +183,7 @@ typedef struct prof_message_t char* plain; GDateTime* timestamp; prof_enc_t enc; + omemo_error_t omemo_err; gboolean trusted; gboolean is_mam; prof_msg_type_t type; diff --git a/tests/unittests/omemo/stub_omemo.c b/tests/unittests/omemo/stub_omemo.c index c445eb23..7d1afd5f 100644 --- a/tests/unittests/omemo/stub_omemo.c +++ b/tests/unittests/omemo/stub_omemo.c @@ -129,6 +129,27 @@ omemo_encrypt_file(FILE* in, FILE* out, off_t file_size, int* gcry_res) }; void omemo_free(void* a) {}; +char* +omemo_on_message_recv(const char* const from, uint32_t sid, + const unsigned char* const iv, size_t iv_len, + GList* keys, const unsigned char* const payload, + size_t payload_len, gboolean muc, gboolean* trusted, omemo_error_t* error) +{ + if (error) { + *error = OMEMO_ERR_NONE; + } + return NULL; +} + +char* +omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_error_t* error) +{ + if (error) { + *error = OMEMO_ERR_NONE; + } + return NULL; +} + uint32_t omemo_device_id() { From 3e2673aad222fc43829ad0924515ed34163d385d Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Sat, 7 Mar 2026 00:52:31 +0100 Subject: [PATCH 7/8] cleanup: Cleanup types --- src/omemo/omemo.c | 20 ++++++++++---------- src/ui/titlebar.c | 6 ++++-- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index 98aa8af6..bf2c842a 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -523,11 +523,11 @@ omemo_set_device_list(const char* const from, GList* device_list) GList* old_list = g_hash_table_lookup(omemo_ctx.device_list, jid->barejid); GList* new_iter; for (new_iter = device_list; new_iter != NULL; new_iter = new_iter->next) { - uint32_t dev_id = GPOINTER_TO_INT(new_iter->data); + uint32_t dev_id = GPOINTER_TO_UINT(new_iter->data); gboolean found = FALSE; GList* old_iter; for (old_iter = old_list; old_iter != NULL; old_iter = old_iter->next) { - if (GPOINTER_TO_INT(old_iter->data) == dev_id) { + if (GPOINTER_TO_UINT(old_iter->data) == dev_id) { found = TRUE; break; } @@ -1259,7 +1259,7 @@ omemo_is_trusted_identity(const char* const jid, const char* const fingerprint) signal_protocol_address address = { .name = jid, .name_len = strlen(jid), - .device_id = GPOINTER_TO_INT(device_id), + .device_id = GPOINTER_TO_UINT(device_id), }; size_t fingerprint_len; @@ -1269,7 +1269,7 @@ omemo_is_trusted_identity(const char* const jid, const char* const fingerprint) buffer = signal_buffer_append(buffer, fingerprint_raw, fingerprint_len); gboolean trusted = is_trusted_identity(&address, signal_buffer_data(buffer), signal_buffer_len(buffer), &omemo_ctx.identity_key_store); - log_debug("[OMEMO] Device trusted %s (%d): %d", jid, GPOINTER_TO_INT(device_id), trusted); + log_debug("[OMEMO] Device trusted %s (%u): %d", jid, GPOINTER_TO_UINT(device_id), trusted); free(fingerprint_raw); signal_buffer_free(buffer); @@ -1291,7 +1291,7 @@ omemo_is_jid_trusted(const char* const jid) 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); + uint32_t device_id = GPOINTER_TO_UINT(device_id_iter->data); if (device_id == omemo_ctx.device_id && equals_our_barejid(jid)) { continue; } @@ -1305,7 +1305,7 @@ omemo_is_jid_trusted(const char* const jid) 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 (device_id == GPOINTER_TO_UINT(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; @@ -1339,7 +1339,7 @@ omemo_get_jid_untrusted_fingerprints(const char* const jid) GList* untrusted_fps = NULL; 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); + uint32_t device_id = GPOINTER_TO_UINT(device_id_iter->data); if (device_id == omemo_ctx.device_id && equals_our_barejid(jid)) { continue; } @@ -1352,7 +1352,7 @@ omemo_get_jid_untrusted_fingerprints(const char* const jid) 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 (device_id == GPOINTER_TO_UINT(g_hash_table_lookup(known_identities, fp_iter->data))) { if (!omemo_is_trusted_identity(jid, fp_iter->data)) { untrusted_fps = g_list_append(untrusted_fps, g_strdup(fp_iter->data)); } @@ -1387,10 +1387,10 @@ omemo_is_device_active(const char* const jid, const char* const fingerprint) return FALSE; } - uint32_t dev_id = GPOINTER_TO_INT(device_id); + uint32_t dev_id = GPOINTER_TO_UINT(device_id); GList* iter; for (iter = device_list; iter != NULL; iter = iter->next) { - if (GPOINTER_TO_INT(iter->data) == dev_id) { + if (GPOINTER_TO_UINT(iter->data) == dev_id) { return TRUE; } } diff --git a/src/ui/titlebar.c b/src/ui/titlebar.c index b18d0b6f..77a9a11c 100644 --- a/src/ui/titlebar.c +++ b/src/ui/titlebar.c @@ -413,10 +413,12 @@ _show_muc_privacy(ProfMucWin* mucwin) { int bracket_attrs = theme_attrs(THEME_TITLE_BRACKET); int encrypted_attrs = theme_attrs(THEME_TITLE_ENCRYPTED); +#ifdef HAVE_OMEMO + int trusted_attrs = theme_attrs(THEME_TITLE_TRUSTED); + int untrusted_attrs = theme_attrs(THEME_TITLE_UNTRUSTED); +#endif 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, "["); From e39ffd981f84dfa103f24838ffa91c7878259e49 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Mon, 9 Mar 2026 08:13:51 +0100 Subject: [PATCH 8/8] refactor: Refactor OMEMO error handling and add non-null attributes 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. --- src/omemo/omemo.c | 38 +++++++++--------------------- src/omemo/omemo.h | 2 +- src/xmpp/omemo.c | 36 +++++++--------------------- src/xmpp/omemo.h | 2 +- tests/unittests/omemo/stub_omemo.c | 8 ++----- 5 files changed, 24 insertions(+), 62 deletions(-) diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index bf2c842a..17f6c836 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -1020,15 +1020,11 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid, auto_jid Jid* sender = NULL; auto_jid Jid* from = jid_create(from_jid); - if (error) { - *error = OMEMO_ERR_NONE; - } + *error = OMEMO_ERR_NONE; if (!from) { log_error("[OMEMO][RECV] Invalid jid %s", from_jid); - if (error) { - *error = OMEMO_ERR_INVALID_JID; - } + *error = OMEMO_ERR_INVALID_JID; return NULL; } @@ -1044,9 +1040,7 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid, if (!key) { log_warning("[OMEMO][RECV] received a message with no corresponding key"); - if (error) { - *error = OMEMO_ERR_NO_KEY; - } + *error = OMEMO_ERR_NO_KEY; return NULL; } @@ -1063,9 +1057,7 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid, g_list_free(roster); if (!sender) { log_warning("[OMEMO][RECV] cannot find MUC message sender fulljid"); - if (error) { - *error = OMEMO_ERR_MUC_SENDER_NOT_FOUND; - } + *error = OMEMO_ERR_MUC_SENDER_NOT_FOUND; return NULL; } } else { @@ -1083,9 +1075,7 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid, res = session_cipher_create(&cipher, omemo_ctx.store, &address, omemo_ctx.signal); if (res != 0) { log_error("[OMEMO][RECV] cannot create session cipher"); - if (error) { - *error = OMEMO_ERR_NO_SESSION; - } + *error = OMEMO_ERR_NO_SESSION; return NULL; } @@ -1145,12 +1135,10 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid, session_cipher_free(cipher); if (res != 0) { log_error("[OMEMO][RECV] cannot decrypt message key: %d", res); - if (error) { - if (!*trusted) { - *error = OMEMO_ERR_NOT_TRUSTED; - } else { - *error = OMEMO_ERR_DECRYPT_FAILED; - } + if (!*trusted) { + *error = OMEMO_ERR_NOT_TRUSTED; + } else { + *error = OMEMO_ERR_DECRYPT_FAILED; } return NULL; } @@ -1158,9 +1146,7 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid, if (signal_buffer_len(plaintext_key) != AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH) { log_error("[OMEMO][RECV] invalid key length"); signal_buffer_free(plaintext_key); - if (error) { - *error = OMEMO_ERR_DECRYPT_FAILED; - } + *error = OMEMO_ERR_DECRYPT_FAILED; return NULL; } @@ -1173,9 +1159,7 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid, if (res != 0) { log_error("[OMEMO][RECV] cannot decrypt message: %s", gcry_strerror(res)); free(plaintext); - if (error) { - *error = OMEMO_ERR_DECRYPT_FAILED; - } + *error = OMEMO_ERR_DECRYPT_FAILED; return NULL; } diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h index 62d28197..bbae2856 100644 --- a/src/omemo/omemo.h +++ b/src/omemo/omemo.h @@ -100,7 +100,7 @@ void omemo_start_device_session(const char* const jid, uint32_t device_id, GList gboolean omemo_loaded(void); char* omemo_on_message_send(ProfWin* win, const char* const message, gboolean request_receipt, gboolean muc, const char* const replace_id); -char* omemo_on_message_recv(const char* const from, uint32_t sid, const unsigned char* const iv, size_t iv_len, GList* keys, const unsigned char* const payload, size_t payload_len, gboolean muc, gboolean* trusted, omemo_error_t* error); +char* omemo_on_message_recv(const char* const from, uint32_t sid, const unsigned char* const iv, size_t iv_len, GList* keys, const unsigned char* const payload, size_t payload_len, gboolean muc, gboolean* trusted, omemo_error_t* error) __attribute__((nonnull(9, 10))); char* omemo_encrypt_file(FILE* in, FILE* out, off_t file_size, int* gcry_res); gcry_error_t omemo_decrypt_file(FILE* in, FILE* out, off_t file_size, const char* fragment); diff --git a/src/xmpp/omemo.c b/src/xmpp/omemo.c index d53b83d7..4e3b52b5 100644 --- a/src/xmpp/omemo.c +++ b/src/xmpp/omemo.c @@ -360,9 +360,7 @@ omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_erro char* iv_text = NULL; char* payload_text = NULL; - if (error) { - *error = OMEMO_ERR_NONE; - } + *error = OMEMO_ERR_NONE; xmpp_stanza_t* encrypted = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_OMEMO); if (!encrypted) { @@ -371,64 +369,48 @@ omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_erro xmpp_stanza_t* header = xmpp_stanza_get_child_by_name(encrypted, "header"); if (!header) { - if (error) { - *error = OMEMO_ERR_OTHER; - } + *error = OMEMO_ERR_OTHER; return NULL; } const char* sid_text = xmpp_stanza_get_attribute(header, "sid"); if (!sid_text) { - if (error) { - *error = OMEMO_ERR_OTHER; - } + *error = OMEMO_ERR_OTHER; return NULL; } uint32_t sid = strtoul(sid_text, NULL, 10); xmpp_stanza_t* iv = xmpp_stanza_get_child_by_name(header, "iv"); if (!iv) { - if (error) { - *error = OMEMO_ERR_OTHER; - } + *error = OMEMO_ERR_OTHER; return NULL; } iv_text = xmpp_stanza_get_text(iv); if (!iv_text) { - if (error) { - *error = OMEMO_ERR_OTHER; - } + *error = OMEMO_ERR_OTHER; return NULL; } size_t iv_len; iv_raw = g_base64_decode(iv_text, &iv_len); if (!iv_raw) { - if (error) { - *error = OMEMO_ERR_OTHER; - } + *error = OMEMO_ERR_OTHER; return NULL; } xmpp_stanza_t* payload = xmpp_stanza_get_child_by_name(encrypted, "payload"); if (!payload) { - if (error) { - *error = OMEMO_ERR_OTHER; - } + *error = OMEMO_ERR_OTHER; goto quit; } payload_text = xmpp_stanza_get_text(payload); if (!payload_text) { - if (error) { - *error = OMEMO_ERR_OTHER; - } + *error = OMEMO_ERR_OTHER; goto quit; } size_t payload_len; payload_raw = g_base64_decode(payload_text, &payload_len); if (!payload_raw) { - if (error) { - *error = OMEMO_ERR_OTHER; - } + *error = OMEMO_ERR_OTHER; goto quit; } diff --git a/src/xmpp/omemo.h b/src/xmpp/omemo.h index e26029e1..622bae49 100644 --- a/src/xmpp/omemo.h +++ b/src/xmpp/omemo.h @@ -45,4 +45,4 @@ void omemo_bundle_publish(gboolean first); void omemo_bundle_request(const char* const jid, uint32_t device_id, ProfIqCallback func, ProfIqFreeCallback free_func, void* userdata); int omemo_start_device_session_handle_bundle(xmpp_stanza_t* const stanza, void* const userdata); -char* omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_error_t* error); +char* omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_error_t* error) __attribute__((nonnull(2, 3))); diff --git a/tests/unittests/omemo/stub_omemo.c b/tests/unittests/omemo/stub_omemo.c index 7d1afd5f..375257bc 100644 --- a/tests/unittests/omemo/stub_omemo.c +++ b/tests/unittests/omemo/stub_omemo.c @@ -135,18 +135,14 @@ omemo_on_message_recv(const char* const from, uint32_t sid, GList* keys, const unsigned char* const payload, size_t payload_len, gboolean muc, gboolean* trusted, omemo_error_t* error) { - if (error) { - *error = OMEMO_ERR_NONE; - } + *error = OMEMO_ERR_NONE; return NULL; } char* omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_error_t* error) { - if (error) { - *error = OMEMO_ERR_NONE; - } + *error = OMEMO_ERR_NONE; return NULL; }