From 0fb27dc4961608eb9b088ca659eb087dd2c1cae7 Mon Sep 17 00:00:00 2001 From: Paul Fariello Date: Tue, 26 Feb 2019 20:33:06 +0140 Subject: Add OMEMO message encryption and decryption --- src/event/client_events.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'src/event/client_events.c') diff --git a/src/event/client_events.c b/src/event/client_events.c index 3b6218ea..76a38b15 100644 --- a/src/event/client_events.c +++ b/src/event/client_events.c @@ -54,6 +54,10 @@ #include "pgp/gpg.h" #endif +#ifdef HAVE_OMEMO +#include "omemo/omemo.h" +#endif + jabber_conn_status_t cl_ev_connect_jid(const char *const jid, const char *const passwd, const char *const altdomain, const int port, const char *const tls_policy) { @@ -203,6 +207,21 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo #endif #endif +#ifdef HAVE_OMEMO + if (chatwin->is_omemo) { + omemo_on_message_send(chatwin, plugin_msg, request_receipt); + } else { + char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt); + chat_log_msg_out(chatwin->barejid, plugin_msg); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt); + free(id); + } + + plugins_post_chat_message_send(chatwin->barejid, plugin_msg); + free(plugin_msg); + return; +#endif + // OTR unsupported, PGP unsupported #ifndef HAVE_LIBOTR #ifndef HAVE_LIBGPGME -- cgit 1.4.1-2-gfad0 From 3e325a61c3feae8513cf61cb4d9620c499cb4c83 Mon Sep 17 00:00:00 2001 From: Paul Fariello Date: Fri, 15 Mar 2019 07:38:05 +0140 Subject: Add support for OMEMO, OTR, PGP built together --- src/event/client_events.c | 97 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 4 deletions(-) (limited to 'src/event/client_events.c') diff --git a/src/event/client_events.c b/src/event/client_events.c index 76a38b15..79ed88f6 100644 --- a/src/event/client_events.c +++ b/src/event/client_events.c @@ -145,9 +145,10 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo return; } -// OTR suported, PGP supported +// OTR suported, PGP supported, OMEMO unsupported #ifdef HAVE_LIBOTR #ifdef HAVE_LIBGPGME +#ifndef HAVE_OMEMO if (chatwin->pgp_send) { char *id = message_send_chat_pgp(chatwin->barejid, plugin_msg, request_receipt); chat_log_pgp_msg_out(chatwin->barejid, plugin_msg); @@ -168,10 +169,12 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo return; #endif #endif +#endif -// OTR supported, PGP unsupported +// OTR supported, PGP unsupported, OMEMO unsupported #ifdef HAVE_LIBOTR #ifndef HAVE_LIBGPGME +#ifndef HAVE_OMEMO gboolean handled = otr_on_message_send(chatwin, plugin_msg, request_receipt); if (!handled) { char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt); @@ -185,10 +188,12 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo return; #endif #endif +#endif -// OTR unsupported, PGP supported +// OTR unsupported, PGP supported, OMEMO unsupported #ifndef HAVE_LIBOTR #ifdef HAVE_LIBGPGME +#ifndef HAVE_OMEMO if (chatwin->pgp_send) { char *id = message_send_chat_pgp(chatwin->barejid, plugin_msg, request_receipt); chat_log_pgp_msg_out(chatwin->barejid, plugin_msg); @@ -206,7 +211,11 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo return; #endif #endif +#endif +// OTR unsupported, PGP unsupported, OMEMO supported +#ifndef HAVE_LIBOTR +#ifndef HAVE_LIBGPGME #ifdef HAVE_OMEMO if (chatwin->is_omemo) { omemo_on_message_send(chatwin, plugin_msg, request_receipt); @@ -221,10 +230,89 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo free(plugin_msg); return; #endif +#endif +#endif + +// OTR supported, PGP unsupported, OMEMO supported +#ifdef HAVE_LIBOTR +#ifndef HAVE_LIBGPGME +#ifdef HAVE_OMEMO + if (chatwin->is_omemo) { + omemo_on_message_send(chatwin, plugin_msg, request_receipt); + } else { + gboolean handled = otr_on_message_send(chatwin, plugin_msg, request_receipt); + if (!handled) { + char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt); + chat_log_msg_out(chatwin->barejid, plugin_msg); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt); + free(id); + } + } + + plugins_post_chat_message_send(chatwin->barejid, plugin_msg); + free(plugin_msg); + return; +#endif +#endif +#endif -// OTR unsupported, PGP unsupported +// OTR unsupported, PGP supported, OMEMO supported +#ifndef HAVE_LIBOTR +#ifdef HAVE_LIBGPGME +#ifdef HAVE_OMEMO + if (chatwin->is_omemo) { + omemo_on_message_send(chatwin, plugin_msg, request_receipt); + } else if (chatwin->pgp_send) { + char *id = message_send_chat_pgp(chatwin->barejid, plugin_msg, request_receipt); + chat_log_pgp_msg_out(chatwin->barejid, plugin_msg); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PGP, request_receipt); + free(id); + } else { + char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt); + chat_log_msg_out(chatwin->barejid, plugin_msg); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt); + free(id); + } + + plugins_post_chat_message_send(chatwin->barejid, plugin_msg); + free(plugin_msg); + return; +#endif +#endif +#endif + +// OTR supported, PGP supported, OMEMO supported +#ifdef HAVE_LIBOTR +#ifdef HAVE_LIBGPGME +#ifdef HAVE_OMEMO + if (chatwin->is_omemo) { + omemo_on_message_send(chatwin, plugin_msg, request_receipt); + } else if (chatwin->pgp_send) { + char *id = message_send_chat_pgp(chatwin->barejid, plugin_msg, request_receipt); + chat_log_pgp_msg_out(chatwin->barejid, plugin_msg); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PGP, request_receipt); + free(id); + } else { + gboolean handled = otr_on_message_send(chatwin, plugin_msg, request_receipt); + if (!handled) { + char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt); + chat_log_msg_out(chatwin->barejid, plugin_msg); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt); + free(id); + } + } + + plugins_post_chat_message_send(chatwin->barejid, plugin_msg); + free(plugin_msg); + return; +#endif +#endif +#endif + +// OTR unsupported, PGP unsupported, OMEMO unsupported #ifndef HAVE_LIBOTR #ifndef HAVE_LIBGPGME +#ifndef HAVE_OMEMO char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt); chat_log_msg_out(chatwin->barejid, plugin_msg); chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt); @@ -235,6 +323,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo return; #endif #endif +#endif } void -- cgit 1.4.1-2-gfad0 From a9d55dec9275c472d7eea2ff79304eda1aefd3be Mon Sep 17 00:00:00 2001 From: Paul Fariello Date: Mon, 18 Mar 2019 07:11:19 +0140 Subject: Add support for sending encrypted message in MUC --- src/event/client_events.c | 23 +++++++-- src/omemo/omemo.c | 127 +++++++++++++++++++++++++++++++--------------- src/omemo/omemo.h | 2 +- src/xmpp/message.c | 14 +++-- src/xmpp/xmpp.h | 2 +- 5 files changed, 118 insertions(+), 50 deletions(-) (limited to 'src/event/client_events.c') diff --git a/src/event/client_events.c b/src/event/client_events.c index 79ed88f6..1488174a 100644 --- a/src/event/client_events.c +++ b/src/event/client_events.c @@ -218,7 +218,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo #ifndef HAVE_LIBGPGME #ifdef HAVE_OMEMO if (chatwin->is_omemo) { - omemo_on_message_send(chatwin, plugin_msg, request_receipt); + omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE); } else { char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt); chat_log_msg_out(chatwin->barejid, plugin_msg); @@ -238,7 +238,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo #ifndef HAVE_LIBGPGME #ifdef HAVE_OMEMO if (chatwin->is_omemo) { - omemo_on_message_send(chatwin, plugin_msg, request_receipt); + omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE); } else { gboolean handled = otr_on_message_send(chatwin, plugin_msg, request_receipt); if (!handled) { @@ -261,7 +261,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo #ifdef HAVE_LIBGPGME #ifdef HAVE_OMEMO if (chatwin->is_omemo) { - omemo_on_message_send(chatwin, plugin_msg, request_receipt); + omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE); } else if (chatwin->pgp_send) { char *id = message_send_chat_pgp(chatwin->barejid, plugin_msg, request_receipt); chat_log_pgp_msg_out(chatwin->barejid, plugin_msg); @@ -286,7 +286,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo #ifdef HAVE_LIBGPGME #ifdef HAVE_OMEMO if (chatwin->is_omemo) { - omemo_on_message_send(chatwin, plugin_msg, request_receipt); + omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE); } else if (chatwin->pgp_send) { char *id = message_send_chat_pgp(chatwin->barejid, plugin_msg, request_receipt); chat_log_pgp_msg_out(chatwin->barejid, plugin_msg); @@ -334,10 +334,25 @@ cl_ev_send_muc_msg(ProfMucWin *mucwin, const char *const msg, const char *const return; } +#ifdef HAVE_OMEMO + if (mucwin->is_omemo) { + omemo_on_message_send((ProfWin *)mucwin, plugin_msg, FALSE, TRUE); + } else { + message_send_groupchat(mucwin->roomjid, plugin_msg, oob_url); + } + + plugins_post_room_message_send(mucwin->roomjid, plugin_msg); + free(plugin_msg); + return; +#endif + +#ifndef HAVE_OMEMO message_send_groupchat(mucwin->roomjid, plugin_msg, oob_url); plugins_post_room_message_send(mucwin->roomjid, plugin_msg); free(plugin_msg); + return; +#endif } void diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index f7a305ee..3fb52b08 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -168,6 +169,7 @@ omemo_init(void) void omemo_on_connect(ProfAccount *account) { + GError *error = NULL; char *omemodir = files_get_data_path(DIR_OMEMO); GString *basedir = g_string_new(omemodir); free(omemodir); @@ -194,18 +196,26 @@ omemo_on_connect(ProfAccount *account) } } + omemo_devicelist_subscribe(); + omemo_ctx.identity_keyfile = g_key_file_new(); - if (g_key_file_load_from_file(omemo_ctx.identity_keyfile, omemo_ctx.identity_filename->str, G_KEY_FILE_KEEP_COMMENTS, NULL)) { + omemo_ctx.sessions_keyfile = g_key_file_new(); + + if (g_key_file_load_from_file(omemo_ctx.identity_keyfile, omemo_ctx.identity_filename->str, G_KEY_FILE_KEEP_COMMENTS, &error)) { load_identity(); omemo_generate_short_term_crypto_materials(account); + } else if (error->code != G_FILE_ERROR_NOENT) { + log_warning("OMEMO: error loading identity from: %s, %s", omemo_ctx.identity_filename->str, error->message); + return; } - omemo_ctx.sessions_keyfile = g_key_file_new(); - if (g_key_file_load_from_file(omemo_ctx.sessions_keyfile, omemo_ctx.sessions_filename->str, G_KEY_FILE_KEEP_COMMENTS, NULL)) { + error = NULL; + if (g_key_file_load_from_file(omemo_ctx.sessions_keyfile, omemo_ctx.sessions_filename->str, G_KEY_FILE_KEEP_COMMENTS, &error)) { load_sessions(); + } else if (error->code != G_FILE_ERROR_NOENT) { + log_warning("OMEMO: error loading sessions from: %s, %s", omemo_ctx.sessions_filename->str, error->message); } - omemo_devicelist_subscribe(); } void @@ -533,22 +543,15 @@ out: } gboolean -omemo_on_message_send(ProfChatWin *chatwin, const char *const message, gboolean request_receipt) +omemo_on_message_send(ProfWin *win, const char *const message, gboolean request_receipt, gboolean muc) { int res; gboolean ret = FALSE; Jid *jid = jid_create(connection_get_fulljid()); GList *keys = NULL; - GList *recipient_device_id = g_hash_table_lookup(omemo_ctx.device_list, chatwin->barejid); - if (!recipient_device_id) { - goto out; - } - GList *sender_device_id = g_hash_table_lookup(omemo_ctx.device_list, jid->barejid); - /* TODO generate fresh AES-GCM materials */ - /* TODO encrypt message */ unsigned char *key; unsigned char *iv; unsigned char *ciphertext; @@ -574,37 +577,72 @@ omemo_on_message_send(ProfChatWin *chatwin, const char *const message, gboolean memcpy(key_tag, key, AES128_GCM_KEY_LENGTH); memcpy(key_tag + AES128_GCM_KEY_LENGTH, tag, AES128_GCM_TAG_LENGTH); + GList *recipients = NULL; + if (muc) { + ProfMucWin *mucwin = (ProfMucWin *)win; + assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); + GList *roster = muc_roster(mucwin->roomjid); + GList *iter; + for (iter = roster; iter != NULL; iter = iter->next) { + Occupant *occupant = (Occupant *)iter->data; + Jid *jid = jid_create(occupant->jid); + if (!jid->barejid) { + log_warning("OMEMO: missing barejid for MUC %s occupant %s", mucwin->roomjid, occupant->nick); + } else { + recipients = g_list_append(recipients, strdup(jid->barejid)); + } + jid_destroy(jid); + } + } else { + ProfChatWin *chatwin = (ProfChatWin *)win; + assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); + recipients = g_list_append(recipients, strdup(chatwin->barejid)); + } + GList *device_ids_iter; - for (device_ids_iter = recipient_device_id; device_ids_iter != NULL; device_ids_iter = device_ids_iter->next) { - int res; - ciphertext_message *ciphertext; - session_cipher *cipher; - signal_protocol_address address = { - .name = chatwin->barejid, - .name_len = strlen(chatwin->barejid), - .device_id = GPOINTER_TO_INT(device_ids_iter->data) - }; - res = session_cipher_create(&cipher, omemo_ctx.store, &address, omemo_ctx.signal); - if (res != 0) { - log_error("OMEMO: cannot create cipher for %s device id %d", address.name, address.device_id); + GList *recipients_iter; + for (recipients_iter = recipients; recipients_iter != NULL; recipients_iter = recipients_iter->next) { + GList *recipient_device_id = NULL; + recipient_device_id = g_hash_table_lookup(omemo_ctx.device_list, recipients_iter->data); + if (!recipient_device_id) { + log_warning("OMEMO: cannot find device ids for %s", recipients_iter->data); continue; } - res = session_cipher_encrypt(cipher, key_tag, AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH, &ciphertext); - if (res != 0) { - log_error("OMEMO: cannot encrypt key for %s device id %d", address.name, address.device_id); - continue; + for (device_ids_iter = recipient_device_id; device_ids_iter != NULL; device_ids_iter = device_ids_iter->next) { + int res; + ciphertext_message *ciphertext; + session_cipher *cipher; + signal_protocol_address address = { + .name = recipients_iter->data, + .name_len = strlen(recipients_iter->data), + .device_id = GPOINTER_TO_INT(device_ids_iter->data) + }; + + res = session_cipher_create(&cipher, omemo_ctx.store, &address, omemo_ctx.signal); + if (res != 0) { + log_error("OMEMO: cannot create cipher for %s device id %d", address.name, address.device_id); + continue; + } + + res = session_cipher_encrypt(cipher, key_tag, AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH, &ciphertext); + if (res != 0) { + log_error("OMEMO: cannot encrypt key for %s device id %d", address.name, address.device_id); + continue; + } + signal_buffer *buffer = ciphertext_message_get_serialized(ciphertext); + omemo_key_t *key = malloc(sizeof(omemo_key_t)); + key->data = signal_buffer_data(buffer); + key->length = signal_buffer_len(buffer); + key->device_id = GPOINTER_TO_INT(device_ids_iter->data); + key->prekey = ciphertext_message_get_type(ciphertext) == CIPHERTEXT_PREKEY_TYPE; + keys = g_list_append(keys, key); } - signal_buffer *buffer = ciphertext_message_get_serialized(ciphertext); - omemo_key_t *key = malloc(sizeof(omemo_key_t)); - key->data = signal_buffer_data(buffer); - key->length = signal_buffer_len(buffer); - key->device_id = GPOINTER_TO_INT(device_ids_iter->data); - key->prekey = ciphertext_message_get_type(ciphertext) == CIPHERTEXT_PREKEY_TYPE; - keys = g_list_append(keys, key); } + g_list_free_full(recipients, free); + for (device_ids_iter = sender_device_id; device_ids_iter != NULL; device_ids_iter = device_ids_iter->next) { int res; ciphertext_message *ciphertext; @@ -635,14 +673,23 @@ omemo_on_message_send(ProfChatWin *chatwin, const char *const message, gboolean keys = g_list_append(keys, key); } - char *id = message_send_chat_omemo(chatwin->barejid, omemo_ctx.device_id, keys, iv, AES128_GCM_IV_LENGTH, ciphertext, ciphertext_len, request_receipt); - chat_log_omemo_msg_out(chatwin->barejid, message); - chatwin_outgoing_msg(chatwin, message, id, PROF_MSG_OMEMO, request_receipt); + if (muc) { + ProfMucWin *mucwin = (ProfMucWin *)win; + assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); + char *id = message_send_chat_omemo(mucwin->roomjid, omemo_ctx.device_id, keys, iv, AES128_GCM_IV_LENGTH, ciphertext, ciphertext_len, request_receipt, TRUE); + free(id); + } else { + ProfChatWin *chatwin = (ProfChatWin *)win; + assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); + char *id = message_send_chat_omemo(chatwin->barejid, omemo_ctx.device_id, keys, iv, AES128_GCM_IV_LENGTH, ciphertext, ciphertext_len, request_receipt, FALSE); + chat_log_omemo_msg_out(chatwin->barejid, message); + chatwin_outgoing_msg(chatwin, message, id, PROF_MSG_OMEMO, request_receipt); + free(id); + } ret = TRUE; out: jid_destroy(jid); - free(id); g_list_free_full(keys, free); free(ciphertext); gcry_free(key); @@ -659,7 +706,7 @@ omemo_on_message_recv(const char *const from_jid, uint32_t sid, const unsigned char *const payload, size_t payload_len, gboolean muc) { unsigned char *plaintext = NULL; - Jid *sender; + Jid *sender = NULL; Jid *from = jid_create(from_jid); if (!from) { log_error("Invalid jid %s", from_jid); diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h index b56b50a5..a8af1a66 100644 --- a/src/omemo/omemo.h +++ b/src/omemo/omemo.h @@ -40,5 +40,5 @@ 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); -gboolean omemo_on_message_send(ProfChatWin *chatwin, const char *const message, gboolean request_receipt); +gboolean omemo_on_message_send(ProfWin *win, const char *const message, gboolean request_receipt, gboolean muc); 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); diff --git a/src/xmpp/message.c b/src/xmpp/message.c index 8fbaedd9..47a21438 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -318,13 +318,19 @@ char* message_send_chat_omemo(const char *const jid, uint32_t sid, GList *keys, const unsigned char *const iv, size_t iv_len, const unsigned char *const ciphertext, size_t ciphertext_len, - gboolean request_receipt) + gboolean request_receipt, gboolean muc) { char *state = chat_session_get_state(jid); xmpp_ctx_t * const ctx = connection_get_ctx(); - char *id = connection_create_stanza_id("msg"); - - xmpp_stanza_t *message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id); + char *id; + xmpp_stanza_t *message; + if (muc) { + id = connection_create_stanza_id("muc"); + message = xmpp_message_new(ctx, STANZA_TYPE_GROUPCHAT, jid, id); + } else { + id = connection_create_stanza_id("msg"); + message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id); + } xmpp_stanza_t *encrypted = xmpp_stanza_new(ctx); xmpp_stanza_set_name(encrypted, "encrypted"); diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index f2eec6c7..6675369a 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -140,7 +140,7 @@ char* message_send_chat(const char *const barejid, const char *const msg, const gboolean request_receipt); char* message_send_chat_otr(const char *const barejid, const char *const msg, gboolean request_receipt); char* message_send_chat_pgp(const char *const barejid, const char *const msg, gboolean request_receipt); -char* message_send_chat_omemo(const char *const jid, uint32_t sid, GList *keys, const unsigned char *const iv, size_t iv_len, const unsigned char *const ciphertext, size_t ciphertext_len, gboolean request_receipt); +char* message_send_chat_omemo(const char *const jid, uint32_t sid, GList *keys, const unsigned char *const iv, size_t iv_len, const unsigned char *const ciphertext, size_t ciphertext_len, gboolean request_receipt, gboolean muc); void message_send_private(const char *const fulljid, const char *const msg, const char *const oob_url); void message_send_groupchat(const char *const roomjid, const char *const msg, const char *const oob_url); void message_send_groupchat_subject(const char *const roomjid, const char *const subject); -- cgit 1.4.1-2-gfad0 From 4e1ffa6bdb89269fa5eff9e5ee2484106d52d149 Mon Sep 17 00:00:00 2001 From: Paul Fariello Date: Mon, 18 Mar 2019 20:30:28 +0140 Subject: Log and print outgoing encrypted message --- src/event/client_events.c | 29 +++++++++++++++---- src/event/server_events.c | 66 +++++++++++++++++++++++++++++++++++-------- src/event/server_events.h | 4 +-- src/log.c | 64 ++++++++++++++++++++++++++++++++++++++++- src/log.h | 7 +++-- src/omemo/omemo.c | 72 ++++++++++++++++++++++------------------------- src/omemo/omemo.h | 2 +- src/ui/mucwin.c | 46 ++++++++++++++++++++++-------- src/ui/ui.h | 3 +- src/ui/window.c | 1 + src/xmpp/message.c | 7 +++-- 11 files changed, 227 insertions(+), 74 deletions(-) (limited to 'src/event/client_events.c') diff --git a/src/event/client_events.c b/src/event/client_events.c index 1488174a..d1cdc797 100644 --- a/src/event/client_events.c +++ b/src/event/client_events.c @@ -218,7 +218,10 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo #ifndef HAVE_LIBGPGME #ifdef HAVE_OMEMO if (chatwin->is_omemo) { - omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE); + char *id = omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE); + chat_log_omemo_msg_out(chatwin->barejid, plugin_msg); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_OMEMO, request_receipt); + free(id); } else { char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt); chat_log_msg_out(chatwin->barejid, plugin_msg); @@ -238,7 +241,10 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo #ifndef HAVE_LIBGPGME #ifdef HAVE_OMEMO if (chatwin->is_omemo) { - omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE); + char *id = omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE); + chat_log_omemo_msg_out(chatwin->barejid, plugin_msg); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_OMEMO, request_receipt); + free(id); } else { gboolean handled = otr_on_message_send(chatwin, plugin_msg, request_receipt); if (!handled) { @@ -261,7 +267,10 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo #ifdef HAVE_LIBGPGME #ifdef HAVE_OMEMO if (chatwin->is_omemo) { - omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE); + char *id = omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE); + chat_log_omemo_msg_out(chatwin->barejid, plugin_msg); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_OMEMO, request_receipt); + free(id); } else if (chatwin->pgp_send) { char *id = message_send_chat_pgp(chatwin->barejid, plugin_msg, request_receipt); chat_log_pgp_msg_out(chatwin->barejid, plugin_msg); @@ -286,7 +295,10 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo #ifdef HAVE_LIBGPGME #ifdef HAVE_OMEMO if (chatwin->is_omemo) { - omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE); + char *id = omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE); + chat_log_omemo_msg_out(chatwin->barejid, plugin_msg); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_OMEMO, request_receipt); + free(id); } else if (chatwin->pgp_send) { char *id = message_send_chat_pgp(chatwin->barejid, plugin_msg, request_receipt); chat_log_pgp_msg_out(chatwin->barejid, plugin_msg); @@ -336,9 +348,14 @@ cl_ev_send_muc_msg(ProfMucWin *mucwin, const char *const msg, const char *const #ifdef HAVE_OMEMO if (mucwin->is_omemo) { - omemo_on_message_send((ProfWin *)mucwin, plugin_msg, FALSE, TRUE); + char *id = omemo_on_message_send((ProfWin *)mucwin, plugin_msg, FALSE, TRUE); + groupchat_log_omemo_msg_out(mucwin->roomjid, plugin_msg); + mucwin_outgoing_msg(mucwin, plugin_msg, PROF_MSG_OMEMO); + free(id); } else { message_send_groupchat(mucwin->roomjid, plugin_msg, oob_url); + groupchat_log_msg_out(mucwin->roomjid, plugin_msg); + mucwin_outgoing_msg(mucwin, plugin_msg, PROF_MSG_PLAIN); } plugins_post_room_message_send(mucwin->roomjid, plugin_msg); @@ -348,6 +365,8 @@ cl_ev_send_muc_msg(ProfMucWin *mucwin, const char *const msg, const char *const #ifndef HAVE_OMEMO message_send_groupchat(mucwin->roomjid, plugin_msg, oob_url); + groupchat_log_msg_out(mucwin->roomjid, plugin_msg); + mucwin_outgoing_msg(mucwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt); plugins_post_room_message_send(mucwin->roomjid, plugin_msg); free(plugin_msg); diff --git a/src/event/server_events.c b/src/event/server_events.c index 7f293198..fd719cc1 100644 --- a/src/event/server_events.c +++ b/src/event/server_events.c @@ -260,21 +260,26 @@ sv_ev_room_history(const char *const room_jid, const char *const nick, } void -sv_ev_room_message(const char *const room_jid, const char *const nick, const char *const message) +sv_ev_room_message(const char *const room_jid, const char *const nick, const char *const message, gboolean omemo) { - if (prefs_get_boolean(PREF_GRLOG)) { - Jid *jid = jid_create(connection_get_fulljid()); - groupchat_log_chat(jid->barejid, room_jid, nick, message); - jid_destroy(jid); - } - ProfMucWin *mucwin = wins_get_muc(room_jid); if (!mucwin) { return; } - char *new_message = plugins_pre_room_message_display(room_jid, nick, message); char *mynick = muc_nick(mucwin->roomjid); + if (g_strcmp0(mynick, nick) == 0) { + /* Ignore message reflection */ + return; + } + + if (omemo) { + groupchat_log_omemo_msg_in(room_jid, nick, message); + } else { + groupchat_log_msg_in(room_jid, nick, message); + } + + char *new_message = plugins_pre_room_message_display(room_jid, nick, message); gboolean whole_word = prefs_get_boolean(PREF_NOTIFY_MENTION_WHOLE_WORD); gboolean case_sensitive = prefs_get_boolean(PREF_NOTIFY_MENTION_CASE_SENSITIVE); @@ -289,7 +294,11 @@ sv_ev_room_message(const char *const room_jid, const char *const nick, const cha GList *triggers = prefs_message_get_triggers(new_message); - mucwin_message(mucwin, nick, new_message, mentions, triggers); + if (omemo) { + mucwin_incoming_msg(mucwin, nick, new_message, mentions, triggers, PROF_MSG_OMEMO); + } else { + mucwin_incoming_msg(mucwin, nick, new_message, mentions, triggers, PROF_MSG_PLAIN); + } g_slist_free(mentions); @@ -607,15 +616,50 @@ sv_ev_incoming_carbon(char *barejid, char *resource, char *message, char *pgp_me } #ifdef HAVE_LIBGPGME +#ifndef HAVE_OMEMO if (pgp_message) { _sv_ev_incoming_pgp(chatwin, new_win, barejid, resource, message, pgp_message, NULL); } else { _sv_ev_incoming_plain(chatwin, new_win, barejid, resource, message, NULL); } -#else - _sv_ev_incoming_plain(chatwin, new_win, barejid, resource, message, NULL); + rosterwin_roster(); + return; +#endif #endif + +#ifdef HAVE_LIBGPGME +#ifdef HAVE_OMEMO + if (pgp_message) { + _sv_ev_incoming_pgp(chatwin, new_win, barejid, resource, message, pgp_message, NULL); + } else if (omemo) { + _sv_ev_incoming_omemo(chatwin, new_win, barejid, resource, message, NULL); + } else { + _sv_ev_incoming_plain(chatwin, new_win, barejid, resource, message, NULL); + } rosterwin_roster(); + return; +#endif +#endif + +#ifndef HAVE_LIBGPGME +#ifdef HAVE_OMEMO + if (omemo) { + _sv_ev_incoming_omemo(chatwin, new_win, barejid, resource, message, NULL); + } else { + _sv_ev_incoming_plain(chatwin, new_win, barejid, resource, message, NULL); + } + rosterwin_roster(); + return; +#endif +#endif + +#ifndef HAVE_LIBGPGME +#ifndef HAVE_OMEMO + _sv_ev_incoming_plain(chatwin, new_win, barejid, resource, message, NULL); + rosterwin_roster(); + return; +#endif +#endif } void diff --git a/src/event/server_events.h b/src/event/server_events.h index 96fdb58c..0fa9989f 100644 --- a/src/event/server_events.h +++ b/src/event/server_events.h @@ -46,9 +46,9 @@ void sv_ev_room_invite(jabber_invite_t invite_type, void sv_ev_room_broadcast(const char *const room_jid, const char *const message); void sv_ev_room_subject(const char *const room, const char *const nick, const char *const subject); void sv_ev_room_history(const char *const room_jid, const char *const nick, - GDateTime *timestamp, const char *const message); + GDateTime *timestamp, const char *const message, gboolean omemo); void sv_ev_room_message(const char *const room_jid, const char *const nick, - const char *const message); + const char *const message, gboolean omemo); void sv_ev_incoming_message(char *barejid, char *resource, char *message, char *pgp_message, GDateTime *timestamp, gboolean omemo); void sv_ev_incoming_private_message(const char *const fulljid, char *message); void sv_ev_delayed_private_message(const char *const fulljid, char *message, GDateTime *timestamp); diff --git a/src/log.c b/src/log.c index 090fd2f8..b679eb1a 100644 --- a/src/log.c +++ b/src/log.c @@ -48,6 +48,7 @@ #include "config/files.h" #include "config/preferences.h" #include "xmpp/xmpp.h" +#include "xmpp/muc.h" #define PROF "prof" @@ -89,6 +90,8 @@ static void _rotate_log_file(void); static char* _log_string_from_level(log_level_t level); static void _chat_log_chat(const char *const login, const char *const other, const gchar *const msg, chat_log_direction_t direction, GDateTime *timestamp); +static void _groupchat_log_chat(const gchar *const login, const gchar *const room, const gchar *const nick, + const gchar *const msg); void log_debug(const char *const msg, ...) @@ -440,7 +443,66 @@ _chat_log_chat(const char *const login, const char *const other, const char *con } void -groupchat_log_chat(const gchar *const login, const gchar *const room, const gchar *const nick, const gchar *const msg) +groupchat_log_msg_out(const gchar *const room, const gchar *const msg) +{ + if (prefs_get_boolean(PREF_GRLOG)) { + const char *jid = connection_get_fulljid(); + Jid *jidp = jid_create(jid); + char *mynick = muc_nick(room); + _groupchat_log_chat(jidp->barejid, room, mynick, msg); + jid_destroy(jidp); + } +} + +void +groupchat_log_msg_in(const gchar *const room, const gchar *const nick, const gchar *const msg) +{ + if (prefs_get_boolean(PREF_GRLOG)) { + const char *jid = connection_get_fulljid(); + Jid *jidp = jid_create(jid); + _groupchat_log_chat(jidp->barejid, room, nick, msg); + jid_destroy(jidp); + } +} + +void +groupchat_log_omemo_msg_out(const gchar *const room, const gchar *const msg) +{ + if (prefs_get_boolean(PREF_CHLOG)) { + const char *jid = connection_get_fulljid(); + Jid *jidp = jid_create(jid); + char *pref_omemo_log = prefs_get_string(PREF_OMEMO_LOG); + char *mynick = muc_nick(room); + if (strcmp(pref_omemo_log, "on") == 0) { + _groupchat_log_chat(jidp->barejid, room, mynick, msg); + } else if (strcmp(pref_omemo_log, "redact") == 0) { + _groupchat_log_chat(jidp->barejid, room, mynick, "[redacted]"); + } + prefs_free_string(pref_omemo_log); + jid_destroy(jidp); + } +} + +void +groupchat_log_omemo_msg_in(const gchar *const room, const gchar *const nick, const gchar *const msg) +{ + if (prefs_get_boolean(PREF_CHLOG)) { + const char *jid = connection_get_fulljid(); + Jid *jidp = jid_create(jid); + char *pref_omemo_log = prefs_get_string(PREF_OMEMO_LOG); + if (strcmp(pref_omemo_log, "on") == 0) { + _groupchat_log_chat(jidp->barejid, room, nick, msg); + } else if (strcmp(pref_omemo_log, "redact") == 0) { + _groupchat_log_chat(jidp->barejid, room, nick, "[redacted]"); + } + prefs_free_string(pref_omemo_log); + jid_destroy(jidp); + } +} + +void +_groupchat_log_chat(const gchar *const login, const gchar *const room, const gchar *const nick, + const gchar *const msg) { struct dated_chat_log *dated_log = g_hash_table_lookup(groupchat_logs, room); diff --git a/src/log.h b/src/log.h index b14231b7..1f45545c 100644 --- a/src/log.h +++ b/src/log.h @@ -82,7 +82,10 @@ void chat_log_close(void); GSList* chat_log_get_previous(const gchar *const login, const gchar *const recipient); void groupchat_log_init(void); -void groupchat_log_chat(const gchar *const login, const gchar *const room, const gchar *const nick, - const gchar *const msg); + +void groupchat_log_msg_out(const gchar *const room, const gchar *const msg); +void groupchat_log_msg_in(const gchar *const room, const gchar *const nick, const gchar *const msg); +void groupchat_log_omemo_msg_out(const gchar *const room, const gchar *const msg); +void groupchat_log_omemo_msg_in(const gchar *const room, const gchar *const nick, const gchar *const msg); #endif diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index 3fb52b08..548c3b9c 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -542,16 +542,14 @@ out: jid_destroy(ownjid); } -gboolean +char * omemo_on_message_send(ProfWin *win, const char *const message, gboolean request_receipt, gboolean muc) { + char *id = NULL; int res; - gboolean ret = FALSE; Jid *jid = jid_create(connection_get_fulljid()); GList *keys = NULL; - GList *sender_device_id = g_hash_table_lookup(omemo_ctx.device_list, jid->barejid); - unsigned char *key; unsigned char *iv; unsigned char *ciphertext; @@ -643,50 +641,48 @@ omemo_on_message_send(ProfWin *win, const char *const message, gboolean request_ g_list_free_full(recipients, free); - for (device_ids_iter = sender_device_id; device_ids_iter != NULL; device_ids_iter = device_ids_iter->next) { - int res; - ciphertext_message *ciphertext; - session_cipher *cipher; - signal_protocol_address address = { - .name = jid->barejid, - .name_len = strlen(jid->barejid), - .device_id = GPOINTER_TO_INT(device_ids_iter->data) - }; - - res = session_cipher_create(&cipher, omemo_ctx.store, &address, omemo_ctx.signal); - if (res != 0) { - log_error("OMEMO: cannot create cipher for %s device id %d", address.name, address.device_id); - continue; - } + if (!muc) { + GList *sender_device_id = g_hash_table_lookup(omemo_ctx.device_list, jid->barejid); + for (device_ids_iter = sender_device_id; device_ids_iter != NULL; device_ids_iter = device_ids_iter->next) { + int res; + ciphertext_message *ciphertext; + session_cipher *cipher; + signal_protocol_address address = { + .name = jid->barejid, + .name_len = strlen(jid->barejid), + .device_id = GPOINTER_TO_INT(device_ids_iter->data) + }; - res = session_cipher_encrypt(cipher, key_tag, AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH, &ciphertext); - if (res != 0) { - log_error("OMEMO: cannot encrypt key for %s device id %d", address.name, address.device_id); - continue; + res = session_cipher_create(&cipher, omemo_ctx.store, &address, omemo_ctx.signal); + if (res != 0) { + log_error("OMEMO: cannot create cipher for %s device id %d", address.name, address.device_id); + continue; + } + + res = session_cipher_encrypt(cipher, key_tag, AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH, &ciphertext); + if (res != 0) { + log_error("OMEMO: cannot encrypt key for %s device id %d", address.name, address.device_id); + continue; + } + signal_buffer *buffer = ciphertext_message_get_serialized(ciphertext); + omemo_key_t *key = malloc(sizeof(omemo_key_t)); + key->data = signal_buffer_data(buffer); + key->length = signal_buffer_len(buffer); + key->device_id = GPOINTER_TO_INT(device_ids_iter->data); + key->prekey = ciphertext_message_get_type(ciphertext) == CIPHERTEXT_PREKEY_TYPE; + keys = g_list_append(keys, key); } - signal_buffer *buffer = ciphertext_message_get_serialized(ciphertext); - omemo_key_t *key = malloc(sizeof(omemo_key_t)); - key->data = signal_buffer_data(buffer); - key->length = signal_buffer_len(buffer); - key->device_id = GPOINTER_TO_INT(device_ids_iter->data); - key->prekey = ciphertext_message_get_type(ciphertext) == CIPHERTEXT_PREKEY_TYPE; - keys = g_list_append(keys, key); } if (muc) { ProfMucWin *mucwin = (ProfMucWin *)win; assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); - char *id = message_send_chat_omemo(mucwin->roomjid, omemo_ctx.device_id, keys, iv, AES128_GCM_IV_LENGTH, ciphertext, ciphertext_len, request_receipt, TRUE); - free(id); + id = message_send_chat_omemo(mucwin->roomjid, omemo_ctx.device_id, keys, iv, AES128_GCM_IV_LENGTH, ciphertext, ciphertext_len, request_receipt, TRUE); } else { ProfChatWin *chatwin = (ProfChatWin *)win; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); - char *id = message_send_chat_omemo(chatwin->barejid, omemo_ctx.device_id, keys, iv, AES128_GCM_IV_LENGTH, ciphertext, ciphertext_len, request_receipt, FALSE); - chat_log_omemo_msg_out(chatwin->barejid, message); - chatwin_outgoing_msg(chatwin, message, id, PROF_MSG_OMEMO, request_receipt); - free(id); + id = message_send_chat_omemo(chatwin->barejid, omemo_ctx.device_id, keys, iv, AES128_GCM_IV_LENGTH, ciphertext, ciphertext_len, request_receipt, FALSE); } - ret = TRUE; out: jid_destroy(jid); @@ -697,7 +693,7 @@ out: gcry_free(tag); gcry_free(key_tag); - return ret; + return id; } char * diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h index a8af1a66..e78bd09b 100644 --- a/src/omemo/omemo.h +++ b/src/omemo/omemo.h @@ -40,5 +40,5 @@ 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); -gboolean omemo_on_message_send(ProfWin *win, const char *const message, gboolean request_receipt, gboolean muc); +char * omemo_on_message_send(ProfWin *win, const char *const message, gboolean request_receipt, gboolean muc); 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); diff --git a/src/ui/mucwin.c b/src/ui/mucwin.c index 0f9f4f2b..abbcd21c 100644 --- a/src/ui/mucwin.c +++ b/src/ui/mucwin.c @@ -478,7 +478,7 @@ _mucwin_print_triggers(ProfWin *window, const char *const message, GList *trigge } void -mucwin_message(ProfMucWin *mucwin, const char *const nick, const char *const message, GSList *mentions, GList *triggers) +mucwin_outgoing_msg(ProfMucWin *mucwin, const char *const message, prof_enc_t enc_mode) { assert(mucwin != NULL); @@ -488,19 +488,43 @@ mucwin_message(ProfMucWin *mucwin, const char *const nick, const char *const mes char ch = '-'; if (mucwin->message_char) { ch = mucwin->message_char[0]; + } else if (enc_mode == PROF_MSG_OTR) { + ch = prefs_get_otr_char(); + } else if (enc_mode == PROF_MSG_PGP) { + ch = prefs_get_pgp_char(); + } else if (enc_mode == PROF_MSG_OMEMO) { + ch = prefs_get_omemo_char(); } - if (g_strcmp0(nick, mynick) != 0) { - if (g_slist_length(mentions) > 0) { - _mucwin_print_mention(window, message, nick, mynick, mentions, &ch); - } else if (triggers) { - win_print_them(window, THEME_ROOMTRIGGER, ch, nick); - _mucwin_print_triggers(window, message, triggers); - } else { - win_println_them_message(window, ch, nick, "%s", message); - } + win_println_me_message(window, ch, mynick, "%s", message); +} + +void +mucwin_incoming_msg(ProfMucWin *mucwin, const char *const nick, const char *const message, GSList *mentions, GList *triggers, prof_enc_t enc_mode) +{ + assert(mucwin != NULL); + + ProfWin *window = (ProfWin*)mucwin; + char *mynick = muc_nick(mucwin->roomjid); + + char ch = '-'; + if (mucwin->message_char) { + ch = mucwin->message_char[0]; + } else if (enc_mode == PROF_MSG_OTR) { + ch = prefs_get_otr_char(); + } else if (enc_mode == PROF_MSG_PGP) { + ch = prefs_get_pgp_char(); + } else if (enc_mode == PROF_MSG_OMEMO) { + ch = prefs_get_omemo_char(); + } + + if (g_slist_length(mentions) > 0) { + _mucwin_print_mention(window, message, nick, mynick, mentions, &ch); + } else if (triggers) { + win_print_them(window, THEME_ROOMTRIGGER, ch, nick); + _mucwin_print_triggers(window, message, triggers); } else { - win_println_me_message(window, ch, mynick, "%s", message); + win_println_them_message(window, ch, nick, "%s", message); } } diff --git a/src/ui/ui.h b/src/ui/ui.h index 95d291b4..e3cece81 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -162,7 +162,8 @@ void mucwin_occupant_role_and_affiliation_change(ProfMucWin *mucwin, const char const char *const role, const char *const affiliation, const char *const actor, const char *const reason); void mucwin_roster(ProfMucWin *mucwin, GList *occupants, const char *const presence); void mucwin_history(ProfMucWin *mucwin, const char *const nick, GDateTime *timestamp, const char *const message); -void mucwin_message(ProfMucWin *mucwin, const char *const nick, const char *const message, GSList *mentions, GList *triggers); +void mucwin_outgoing_msg(ProfMucWin *mucwin, const char *const message, prof_enc_t enc_mode); +void mucwin_incoming_msg(ProfMucWin *mucwin, const char *const nick, const char *const message, GSList *mentions, GList *triggers, prof_enc_t enc_mode); void mucwin_subject(ProfMucWin *mucwin, const char *const nick, const char *const subject); void mucwin_requires_config(ProfMucWin *mucwin); void mucwin_info(ProfMucWin *mucwin); diff --git a/src/ui/window.c b/src/ui/window.c index ef0f93d2..64b04365 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -197,6 +197,7 @@ win_create_muc(const char *const roomjid) } new_win->enctext = NULL; new_win->message_char = NULL; + new_win->is_omemo = FALSE; new_win->memcheck = PROFMUCWIN_MEMCHECK; diff --git a/src/xmpp/message.c b/src/xmpp/message.c index 47a21438..cc3d66bd 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -729,8 +729,11 @@ _handle_groupchat(xmpp_stanza_t *const stanza) return; } + // check omemo encryption + gboolean omemo = FALSE; #ifdef HAVE_OMEMO message = omemo_receive_message(stanza); + omemo = message != NULL; #endif if (!message) { @@ -744,10 +747,10 @@ _handle_groupchat(xmpp_stanza_t *const stanza) // determine if the notifications happened whilst offline GDateTime *timestamp = stanza_get_delay(stanza); if (timestamp) { - sv_ev_room_history(jid->barejid, jid->resourcepart, timestamp, message); + sv_ev_room_history(jid->barejid, jid->resourcepart, timestamp, message, omemo); g_date_time_unref(timestamp); } else { - sv_ev_room_message(jid->barejid, jid->resourcepart, message); + sv_ev_room_message(jid->barejid, jid->resourcepart, message, omemo); } xmpp_free(ctx, message); -- cgit 1.4.1-2-gfad0 From 91ee289c773a137c60e98c1e62db41346eb57363 Mon Sep 17 00:00:00 2001 From: Paul Fariello Date: Fri, 22 Mar 2019 00:03:16 +0100 Subject: Add support for disconnect in OMEMO --- src/event/client_events.c | 3 ++ src/omemo/omemo.c | 98 ++++++++++++++++++++++++++++++++++++----------- src/omemo/omemo.h | 4 +- src/omemo/store.c | 16 ++++++-- src/xmpp/message.c | 1 + src/xmpp/omemo.c | 42 +++++++++++++++----- src/xmpp/stanza.c | 16 ++++++-- 7 files changed, 140 insertions(+), 40 deletions(-) (limited to 'src/event/client_events.c') diff --git a/src/event/client_events.c b/src/event/client_events.c index d1cdc797..adcffbf2 100644 --- a/src/event/client_events.c +++ b/src/event/client_events.c @@ -98,6 +98,9 @@ cl_ev_disconnect(void) #ifdef HAVE_LIBGPGME p_gpg_on_disconnect(); #endif +#ifdef HAVE_OMEMO + omemo_on_disconnect(); +#endif } void diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index 6e723891..8ec0554f 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -35,7 +35,6 @@ static void unlock(void *user_data); static void omemo_log(int level, const char *message, size_t len, void *user_data); static gboolean handle_own_device_list(const char *const jid, GList *device_list); static gboolean handle_device_list_start_session(const char *const jid, GList *device_list); -static void free_omemo_key(omemo_key_t *key); static char * omemo_fingerprint(ec_public_key *identity, gboolean formatted); static unsigned char *omemo_fingerprint_decode(const char *const fingerprint, size_t *len); static void cache_device_identity(const char *const jid, uint32_t device_id, ec_public_key *identity); @@ -196,6 +195,8 @@ omemo_on_connect(ProfAccount *account) } } + g_string_free(basedir, TRUE); + omemo_devicelist_subscribe(); omemo_ctx.identity_keyfile = g_key_file_new(); @@ -218,6 +219,28 @@ omemo_on_connect(ProfAccount *account) } +void +omemo_on_disconnect(void) +{ + signal_protocol_signed_pre_key_remove_key(omemo_ctx.store, omemo_ctx.signed_pre_key_id); + g_hash_table_free(omemo_ctx.signed_pre_key_store); + + GHashTableIter iter; + gpointer id; + + g_hash_table_iter_init(&iter, omemo_ctx.pre_key_store); + while (g_hash_table_iter_next(&iter, &id, NULL)) { + signal_protocol_pre_key_remove_key(omemo_ctx.store, GPOINTER_TO_INT(id)); + } + + g_hash_table_free(omemo_ctx.pre_key_store); + + g_string_free(omemo_ctx.identity_filename, TRUE); + g_key_file_free(omemo_ctx.identity_keyfile); + g_string_free(omemo_ctx.sessions_filename, TRUE); + g_key_file_free(omemo_ctx.sessions_keyfile); +} + void omemo_generate_crypto_materials(ProfAccount *account) { @@ -261,6 +284,13 @@ omemo_generate_short_term_crypto_materials(ProfAccount *account) signal_protocol_key_helper_pre_key_list_node *pre_keys_head; signal_protocol_key_helper_generate_pre_keys(&pre_keys_head, start, 100, omemo_ctx.signal); + signal_protocol_key_helper_pre_key_list_node *p; + for (p = pre_keys_head; p != NULL; p = signal_protocol_key_helper_key_list_next(p)) { + session_pre_key *prekey = signal_protocol_key_helper_key_list_element(p); + signal_protocol_pre_key_store_key(omemo_ctx.store, prekey); + } + signal_protocol_key_helper_key_list_free(pre_keys_head); + session_signed_pre_key *signed_pre_key; struct timeval tv; gettimeofday(&tv, NULL); @@ -268,13 +298,8 @@ omemo_generate_short_term_crypto_materials(ProfAccount *account) omemo_ctx.signed_pre_key_id = 1; signal_protocol_key_helper_generate_signed_pre_key(&signed_pre_key, omemo_ctx.identity_key_pair, omemo_ctx.signed_pre_key_id, timestamp, omemo_ctx.signal); - - signal_protocol_key_helper_pre_key_list_node *p; - for (p = pre_keys_head; p != NULL; p = signal_protocol_key_helper_key_list_next(p)) { - session_pre_key *prekey = signal_protocol_key_helper_key_list_element(p); - signal_protocol_pre_key_store_key(omemo_ctx.store, prekey); - } signal_protocol_signed_pre_key_store_key(omemo_ctx.store, signed_pre_key); + SIGNAL_UNREF(signed_pre_key); loaded = TRUE; @@ -315,6 +340,7 @@ omemo_start_muc_sessions(const char *const roomjid) omemo_start_session(jid->barejid); jid_destroy(jid); } + g_list_free(roster); } gboolean @@ -348,6 +374,7 @@ omemo_signed_prekey(unsigned char **output, size_t *length) signal_protocol_signed_pre_key_load_key(omemo_ctx.store, &signed_pre_key, omemo_ctx.signed_pre_key_id); ec_public_key_serialize(&buffer, ec_key_pair_get_public(session_signed_pre_key_get_key_pair(signed_pre_key))); + SIGNAL_UNREF(signed_pre_key); *length = signal_buffer_len(buffer); *output = malloc(*length); memcpy(*output, signal_buffer_data(buffer), *length); @@ -363,6 +390,7 @@ omemo_signed_prekey_signature(unsigned char **output, size_t *length) *length = session_signed_pre_key_get_signature_len(signed_pre_key); *output = malloc(*length); memcpy(*output, session_signed_pre_key_get_signature(signed_pre_key), *length); + SIGNAL_UNREF(signed_pre_key); } void @@ -382,9 +410,12 @@ omemo_prekeys(GList **prekeys, GList **ids, GList **lengths) signal_buffer *public_key; ec_public_key_serialize(&public_key, ec_key_pair_get_public(session_pre_key_get_key_pair(pre_key))); + SIGNAL_UNREF(pre_key); size_t length = signal_buffer_len(public_key); unsigned char *prekey_value = malloc(length); memcpy(prekey_value, signal_buffer_data(public_key), length); + signal_buffer_free(public_key); + *prekeys = g_list_append(*prekeys, prekey_value); *ids = g_list_append(*ids, GINT_TO_POINTER(id)); *lengths = g_list_append(*lengths, GINT_TO_POINTER(length)); @@ -454,7 +485,7 @@ omemo_start_device_session(const char *const jid, uint32_t device_id, const unsigned char *const identity_key_raw, size_t identity_key_len) { signal_protocol_address address = { - .name = strdup(jid), + .name = jid, .name_len = strlen(jid), .device_id = device_id, }; @@ -538,7 +569,7 @@ omemo_start_device_session(const char *const jid, uint32_t device_id, } out: - g_list_free_full(prekeys, (GDestroyNotify)free_omemo_key); + SIGNAL_UNREF(identity_key); jid_destroy(ownjid); } @@ -591,6 +622,7 @@ omemo_on_message_send(ProfWin *win, const char *const message, gboolean request_ } jid_destroy(jid); } + g_list_free(roster); } else { ProfChatWin *chatwin = (ProfChatWin *)win; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); @@ -625,17 +657,20 @@ omemo_on_message_send(ProfWin *win, const char *const message, gboolean request_ } res = session_cipher_encrypt(cipher, key_tag, AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH, &ciphertext); + session_cipher_free(cipher); if (res != 0) { log_error("OMEMO: cannot encrypt key for %s device id %d", address.name, address.device_id); continue; } signal_buffer *buffer = ciphertext_message_get_serialized(ciphertext); omemo_key_t *key = malloc(sizeof(omemo_key_t)); - key->data = signal_buffer_data(buffer); key->length = signal_buffer_len(buffer); + key->data = malloc(key->length); + memcpy(key->data, signal_buffer_data(buffer), key->length); key->device_id = GPOINTER_TO_INT(device_ids_iter->data); key->prekey = ciphertext_message_get_type(ciphertext) == CIPHERTEXT_PREKEY_TYPE; keys = g_list_append(keys, key); + SIGNAL_UNREF(ciphertext); } } @@ -660,17 +695,20 @@ omemo_on_message_send(ProfWin *win, const char *const message, gboolean request_ } res = session_cipher_encrypt(cipher, key_tag, AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH, &ciphertext); + session_cipher_free(cipher); if (res != 0) { log_error("OMEMO: cannot encrypt key for %s device id %d", address.name, address.device_id); continue; } signal_buffer *buffer = ciphertext_message_get_serialized(ciphertext); omemo_key_t *key = malloc(sizeof(omemo_key_t)); - key->data = signal_buffer_data(buffer); key->length = signal_buffer_len(buffer); + key->data = malloc(key->length); + memcpy(key->data, signal_buffer_data(buffer), key->length); key->device_id = GPOINTER_TO_INT(device_ids_iter->data); key->prekey = ciphertext_message_get_type(ciphertext) == CIPHERTEXT_PREKEY_TYPE; keys = g_list_append(keys, key); + SIGNAL_UNREF(ciphertext); } } @@ -686,7 +724,7 @@ omemo_on_message_send(ProfWin *win, const char *const message, gboolean request_ out: jid_destroy(jid); - g_list_free_full(keys, free); + g_list_free_full(keys, (GDestroyNotify)omemo_key_free); free(ciphertext); gcry_free(key); gcry_free(iv); @@ -734,6 +772,7 @@ omemo_on_message_recv(const char *const from_jid, uint32_t sid, break; } } + g_list_free(roster); if (!sender) { log_warning("OMEMO: cannot find MUC message sender fulljid"); goto out; @@ -770,6 +809,9 @@ omemo_on_message_recv(const char *const from_jid, uint32_t sid, curve_generate_key_pair(omemo_ctx.signal, &ec_pair); session_pre_key_create(&new_pre_key, pre_key_id, ec_pair); signal_protocol_pre_key_store_key(omemo_ctx.store, new_pre_key); + SIGNAL_UNREF(new_pre_key); + SIGNAL_UNREF(message); + SIGNAL_UNREF(ec_pair); omemo_bundle_publish(); if (res == 0) { @@ -781,16 +823,19 @@ omemo_on_message_recv(const char *const from_jid, uint32_t sid, signal_message *message; signal_message_deserialize(&message, key->data, key->length, omemo_ctx.signal); res = session_cipher_decrypt_signal_message(cipher, message, NULL, &plaintext_key); + SIGNAL_UNREF(message); } + + session_cipher_free(cipher); if (res != 0) { log_error("OMEMO: cannot decrypt message key"); - return NULL; + goto out; } if (signal_buffer_len(plaintext_key) != AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH) { log_error("OMEMO: invalid key length"); signal_buffer_free(plaintext_key); - return NULL; + goto out; } size_t plaintext_len = payload_len; @@ -798,11 +843,12 @@ omemo_on_message_recv(const char *const from_jid, uint32_t sid, res = aes128gcm_decrypt(plaintext, &plaintext_len, payload, payload_len, iv, signal_buffer_data(plaintext_key), signal_buffer_data(plaintext_key) + AES128_GCM_KEY_LENGTH); + signal_buffer_free(plaintext_key); if (res != 0) { log_error("OMEMO: cannot decrypt message: %s", gcry_strerror(res)); - signal_buffer_free(plaintext_key); free(plaintext); - return NULL; + plaintext = NULL; + goto out; } plaintext[plaintext_len] = '\0'; @@ -1040,14 +1086,14 @@ handle_device_list_start_session(const char *const jid, GList *device_list) return FALSE; } -static void -free_omemo_key(omemo_key_t *key) +void +omemo_key_free(omemo_key_t *key) { if (key == NULL) { return; } - free((void *)key->data); + free(key->data); free(key); } @@ -1062,13 +1108,14 @@ load_identity(void) char *identity_key_public_b64 = g_key_file_get_string(omemo_ctx.identity_keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_IDENTITY_KEY_PUBLIC, NULL); size_t identity_key_public_len; unsigned char *identity_key_public = g_base64_decode(identity_key_public_b64, &identity_key_public_len); + g_free(identity_key_public_b64); omemo_ctx.identity_key_store.public = signal_buffer_create(identity_key_public, identity_key_public_len); char *identity_key_private_b64 = g_key_file_get_string(omemo_ctx.identity_keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_IDENTITY_KEY_PRIVATE, NULL); size_t identity_key_private_len; unsigned char *identity_key_private = g_base64_decode(identity_key_private_b64, &identity_key_private_len); + g_free(identity_key_private_b64); omemo_ctx.identity_key_store.private = signal_buffer_create(identity_key_private, identity_key_private_len); - signal_buffer_create(identity_key_private, identity_key_private_len); ec_public_key *public_key; curve_decode_point(&public_key, identity_key_public, identity_key_public_len, omemo_ctx.signal); @@ -1086,11 +1133,13 @@ load_identity(void) char *key_b64 = g_key_file_get_string(omemo_ctx.identity_keyfile, OMEMO_STORE_GROUP_TRUST, keys[i], NULL); size_t key_len; unsigned char *key = g_base64_decode(key_b64, &key_len); + g_free(key_b64); signal_buffer *buffer = signal_buffer_create(key, key_len); - g_hash_table_insert(omemo_ctx.identity_key_store.trusted, keys[i], buffer); - free(key_b64); + g_free(key); + g_hash_table_insert(omemo_ctx.identity_key_store.trusted, strdup(keys[i]), buffer); } } + g_strfreev(keys); } static void @@ -1115,11 +1164,14 @@ load_sessions(void) char *record_b64 = g_key_file_get_string(omemo_ctx.sessions_keyfile, groups[i], keys[j], NULL); size_t record_len; unsigned char *record = g_base64_decode(record_b64, &record_len); + g_free(record_b64); signal_buffer *buffer = signal_buffer_create(record, record_len); + g_free(record); g_hash_table_insert(device_store, GINT_TO_POINTER(id), buffer); - free(record_b64); } + g_strfreev(keys); } + free(groups); } } diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h index e78bd09b..e9e9cf8d 100644 --- a/src/omemo/omemo.h +++ b/src/omemo/omemo.h @@ -9,7 +9,7 @@ typedef struct omemo_context_t omemo_context; typedef struct omemo_key { - const unsigned char *data; + unsigned char *data; size_t length; gboolean prekey; uint32_t device_id; @@ -18,7 +18,9 @@ typedef struct omemo_key { void omemo_init(void); void omemo_on_connect(ProfAccount *account); +void omemo_on_disconnect(void); void omemo_generate_crypto_materials(ProfAccount *account); +void omemo_key_free(omemo_key_t *key); uint32_t omemo_device_id(void); void omemo_identity_key(unsigned char **output, size_t *length); diff --git a/src/omemo/store.c b/src/omemo/store.c index 621c902c..4b20d29f 100644 --- a/src/omemo/store.c +++ b/src/omemo/store.c @@ -109,7 +109,10 @@ store_session(const signal_protocol_address *address, char *record_b64 = g_base64_encode(record, record_len); - g_key_file_set_string(omemo_sessions_keyfile(), address->name, g_strdup_printf("%d", address->device_id), record_b64); + char *device_id = g_strdup_printf("%d", address->device_id); + g_key_file_set_string(omemo_sessions_keyfile(), address->name, device_id, record_b64); + free(device_id); + g_free(record_b64); omemo_sessions_keyfile_save(); @@ -283,9 +286,10 @@ save_identity(const signal_protocol_address *address, uint8_t *key_data, char *key_b64 = g_base64_encode(key_data, key_len); g_key_file_set_string(omemo_identity_keyfile(), OMEMO_STORE_GROUP_TRUST, node, key_b64); + g_free(key_b64); omemo_identity_keyfile_save(); - free(node); + g_free(node); return SG_SUCCESS; } @@ -294,13 +298,19 @@ int is_trusted_identity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data) { + int ret; identity_key_store_t *identity_key_store = (identity_key_store_t *)user_data; char *node = g_strdup_printf("%s:%d", address->name, address->device_id); signal_buffer *buffer = signal_buffer_create(key_data, key_len); signal_buffer *original = g_hash_table_lookup(identity_key_store->trusted, node); + g_free(node); - return original != NULL && signal_buffer_compare(buffer, original) == 0; + ret = original != NULL && signal_buffer_compare(buffer, original) == 0; + + signal_buffer_free(buffer); + + return ret; } int diff --git a/src/xmpp/message.c b/src/xmpp/message.c index cc3d66bd..bc166111 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -405,6 +405,7 @@ message_send_chat_omemo(const char *const jid, uint32_t sid, GList *keys, xmpp_stanza_add_child(body, body_text); xmpp_stanza_release(body_text); xmpp_stanza_add_child(message, body); + xmpp_stanza_release(body); if (state) { stanza_attach_state(ctx, message, state); diff --git a/src/xmpp/omemo.c b/src/xmpp/omemo.c index 1a10e374..6c57781b 100644 --- a/src/xmpp/omemo.c +++ b/src/xmpp/omemo.c @@ -70,6 +70,10 @@ omemo_bundle_publish(void) signed_prekey_signature, signed_prekey_signature_length, prekeys, ids, lengths); + g_list_free_full(prekeys, free); + g_list_free(lengths); + g_list_free(ids); + Jid *jid = jid_create(connection_get_fulljid()); if (caps_jid_has_feature(jid->barejid, XMPP_FEATURE_PUBSUB_PUBLISH_OPTIONS)) { stanza_attach_publish_options(ctx, iq, "pubsub#access_model", "open"); @@ -157,7 +161,9 @@ omemo_start_device_session_handle_bundle(xmpp_stanza_t *const stanza, void *cons if (!prekey_text) { return 1; } - key->data = g_base64_decode(xmpp_stanza_get_text(prekey_text), &key->length); + char *prekey_b64 = xmpp_stanza_get_text(prekey_text); + key->data = g_base64_decode(prekey_b64, &key->length); + free(prekey_b64); key->prekey = TRUE; key->device_id = device_id; @@ -178,7 +184,9 @@ omemo_start_device_session_handle_bundle(xmpp_stanza_t *const stanza, void *cons return 1; } size_t signed_prekey_len; - unsigned char *signed_prekey_raw = g_base64_decode(xmpp_stanza_get_text(signed_prekey_text), &signed_prekey_len); + char *signed_prekey_b64 = xmpp_stanza_get_text(signed_prekey_text); + unsigned char *signed_prekey_raw = g_base64_decode(signed_prekey_b64, &signed_prekey_len); + free(signed_prekey_b64); xmpp_stanza_t *signed_prekey_signature = xmpp_stanza_get_child_by_name(bundle, "signedPreKeySignature"); if (!signed_prekey_signature) { @@ -189,7 +197,9 @@ omemo_start_device_session_handle_bundle(xmpp_stanza_t *const stanza, void *cons return 1; } size_t signed_prekey_signature_len; - unsigned char *signed_prekey_signature_raw = g_base64_decode(xmpp_stanza_get_text(signed_prekey_signature_text), &signed_prekey_signature_len); + char *signed_prekey_signature_b64 = xmpp_stanza_get_text(signed_prekey_signature_text); + unsigned char *signed_prekey_signature_raw = g_base64_decode(signed_prekey_signature_b64, &signed_prekey_signature_len); + free(signed_prekey_signature_b64); xmpp_stanza_t *identity_key = xmpp_stanza_get_child_by_name(bundle, "identityKey"); if (!identity_key) { @@ -200,11 +210,18 @@ omemo_start_device_session_handle_bundle(xmpp_stanza_t *const stanza, void *cons return 1; } size_t identity_key_len; - unsigned char *identity_key_raw = g_base64_decode(xmpp_stanza_get_text(identity_key_text), &identity_key_len); + char *identity_key_b64 = xmpp_stanza_get_text(identity_key_text); + unsigned char *identity_key_raw = g_base64_decode(identity_key_b64, &identity_key_len); + free(identity_key_b64); omemo_start_device_session(from, device_id, prekeys_list, signed_prekey_id, signed_prekey_raw, signed_prekey_len, signed_prekey_signature_raw, signed_prekey_signature_len, identity_key_raw, identity_key_len); + + g_list_free_full(prekeys_list, (GDestroyNotify)omemo_key_free); + g_free(signed_prekey_raw); + g_free(identity_key_raw); + g_free(signed_prekey_signature_raw); return 1; } @@ -233,23 +250,23 @@ omemo_receive_message(xmpp_stanza_t *const stanza) if (!iv) { return NULL; } - const char *iv_text = xmpp_stanza_get_text(iv); + char *iv_text = xmpp_stanza_get_text(iv); if (!iv_text) { return NULL; } size_t iv_len; - const unsigned char *iv_raw = g_base64_decode(iv_text, &iv_len); + unsigned char *iv_raw = g_base64_decode(iv_text, &iv_len); xmpp_stanza_t *payload = xmpp_stanza_get_child_by_name(encrypted, "payload"); if (!payload) { return NULL; } - const char *payload_text = xmpp_stanza_get_text(payload); + char *payload_text = xmpp_stanza_get_text(payload); if (!payload_text) { return NULL; } size_t payload_len; - const unsigned char *payload_raw = g_base64_decode(payload_text, &payload_len); + unsigned char *payload_raw = g_base64_decode(payload_text, &payload_len); GList *keys = NULL; xmpp_stanza_t *key_stanza; @@ -259,7 +276,7 @@ omemo_receive_message(xmpp_stanza_t *const stanza) } omemo_key_t *key = malloc(sizeof(omemo_key_t)); - const char *key_text = xmpp_stanza_get_text(key_stanza); + char *key_text = xmpp_stanza_get_text(key_stanza); if (!key_text) { goto skip; } @@ -271,6 +288,7 @@ omemo_receive_message(xmpp_stanza_t *const stanza) goto skip; } key->data = g_base64_decode(key_text, &key->length); + free(key_text); key->prekey = g_strcmp0(xmpp_stanza_get_attribute(key_stanza, "prekey"), "true") == 0; keys = g_list_append(keys, key); continue; @@ -285,6 +303,12 @@ skip: keys, payload_raw, payload_len, g_strcmp0(type, STANZA_TYPE_GROUPCHAT) == 0); + g_list_free_full(keys, (GDestroyNotify)omemo_key_free); + g_free(iv_raw); + g_free(payload_raw); + g_free(iv_text); + g_free(payload_text); + return plaintext; } diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 65a6e02b..b6992e82 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -2274,7 +2274,9 @@ stanza_create_omemo_bundle_publish(xmpp_ctx_t *ctx, uint32_t device_id, xmpp_stanza_set_attribute(signed_prekey_public_stanza, "signedPreKeyId", "1"); xmpp_stanza_t *signed_prekey_public_stanza_text= xmpp_stanza_new(ctx); - xmpp_stanza_set_text(signed_prekey_public_stanza_text, g_base64_encode(signed_prekey, signed_prekey_length)); + char *signed_prekey_b64 = g_base64_encode(signed_prekey, signed_prekey_length); + xmpp_stanza_set_text(signed_prekey_public_stanza_text, signed_prekey_b64); + g_free(signed_prekey_b64); xmpp_stanza_add_child(signed_prekey_public_stanza, signed_prekey_public_stanza_text); xmpp_stanza_release(signed_prekey_public_stanza_text); @@ -2282,7 +2284,9 @@ stanza_create_omemo_bundle_publish(xmpp_ctx_t *ctx, uint32_t device_id, xmpp_stanza_set_name(signed_prekey_signature_stanza , "signedPreKeySignature"); xmpp_stanza_t *signed_prekey_signature_stanza_text= xmpp_stanza_new(ctx); - xmpp_stanza_set_text(signed_prekey_signature_stanza_text, g_base64_encode(signed_prekey_signature, signed_prekey_signature_length)); + char *signed_prekey_signature_b64 = g_base64_encode(signed_prekey_signature, signed_prekey_signature_length); + xmpp_stanza_set_text(signed_prekey_signature_stanza_text, signed_prekey_signature_b64); + g_free(signed_prekey_signature_b64); xmpp_stanza_add_child(signed_prekey_signature_stanza, signed_prekey_signature_stanza_text); xmpp_stanza_release(signed_prekey_signature_stanza_text); @@ -2290,7 +2294,9 @@ stanza_create_omemo_bundle_publish(xmpp_ctx_t *ctx, uint32_t device_id, xmpp_stanza_set_name(identity_key_stanza , "identityKey"); xmpp_stanza_t *identity_key_stanza_text= xmpp_stanza_new(ctx); - xmpp_stanza_set_text(identity_key_stanza_text, g_base64_encode(identity_key, identity_key_length)); + char *identity_key_b64 = g_base64_encode(identity_key, identity_key_length); + xmpp_stanza_set_text(identity_key_stanza_text, identity_key_b64); + g_free(identity_key_b64); xmpp_stanza_add_child(identity_key_stanza, identity_key_stanza_text); xmpp_stanza_release(identity_key_stanza_text); @@ -2306,7 +2312,9 @@ stanza_create_omemo_bundle_publish(xmpp_ctx_t *ctx, uint32_t device_id, g_free(id); xmpp_stanza_t *prekey_text = xmpp_stanza_new(ctx); - xmpp_stanza_set_text(prekey_text, g_base64_encode(p->data, GPOINTER_TO_INT(l->data))); + char *prekey_b64 = g_base64_encode(p->data, GPOINTER_TO_INT(l->data)); + xmpp_stanza_set_text(prekey_text, prekey_b64); + g_free(prekey_b64); xmpp_stanza_add_child(prekey, prekey_text); xmpp_stanza_add_child(prekeys_stanza, prekey); -- cgit 1.4.1-2-gfad0 From e69f947547160ea2c965a3d4f5966c5f4a289340 Mon Sep 17 00:00:00 2001 From: Paul Fariello Date: Mon, 1 Apr 2019 20:39:39 +0320 Subject: Rework MUC reflected message filtering Reflected messages can't be filtered by nick only otherwise you might ignore messages comming from you on another devices. Consequently we maintain a list of sent messages id in mucwin. To be sure the id will be correctly reflected we use the origin-id stanza. --- src/event/client_events.c | 12 +++++++----- src/event/server_events.c | 10 +++------- src/event/server_events.h | 2 +- src/ui/mucwin.c | 11 +++++++++-- src/ui/ui.h | 4 ++-- src/ui/win_types.h | 1 + src/ui/window.c | 1 + src/ui/window_list.c | 1 + src/xmpp/message.c | 18 ++++++++++++++---- src/xmpp/stanza.c | 15 +++++++++++++++ src/xmpp/stanza.h | 3 +++ src/xmpp/xmpp.h | 2 +- tests/unittests/ui/stub_ui.c | 4 ++-- tests/unittests/xmpp/stub_xmpp.c | 5 ++++- 14 files changed, 64 insertions(+), 25 deletions(-) (limited to 'src/event/client_events.c') diff --git a/src/event/client_events.c b/src/event/client_events.c index adcffbf2..c2149985 100644 --- a/src/event/client_events.c +++ b/src/event/client_events.c @@ -353,12 +353,13 @@ cl_ev_send_muc_msg(ProfMucWin *mucwin, const char *const msg, const char *const if (mucwin->is_omemo) { char *id = omemo_on_message_send((ProfWin *)mucwin, plugin_msg, FALSE, TRUE); groupchat_log_omemo_msg_out(mucwin->roomjid, plugin_msg); - mucwin_outgoing_msg(mucwin, plugin_msg, PROF_MSG_OMEMO); + mucwin_outgoing_msg(mucwin, plugin_msg, id, PROF_MSG_OMEMO); free(id); } else { - message_send_groupchat(mucwin->roomjid, plugin_msg, oob_url); + char *id = message_send_groupchat(mucwin->roomjid, plugin_msg, oob_url); groupchat_log_msg_out(mucwin->roomjid, plugin_msg); - mucwin_outgoing_msg(mucwin, plugin_msg, PROF_MSG_PLAIN); + mucwin_outgoing_msg(mucwin, plugin_msg, id, PROF_MSG_PLAIN); + free(id); } plugins_post_room_message_send(mucwin->roomjid, plugin_msg); @@ -367,9 +368,10 @@ cl_ev_send_muc_msg(ProfMucWin *mucwin, const char *const msg, const char *const #endif #ifndef HAVE_OMEMO - message_send_groupchat(mucwin->roomjid, plugin_msg, oob_url); + char *id = message_send_groupchat(mucwin->roomjid, plugin_msg, oob_url); groupchat_log_msg_out(mucwin->roomjid, plugin_msg); - mucwin_outgoing_msg(mucwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt); + mucwin_outgoing_msg(mucwin, plugin_msg, id, PROF_MSG_PLAIN); + free(id); plugins_post_room_message_send(mucwin->roomjid, plugin_msg); free(plugin_msg); diff --git a/src/event/server_events.c b/src/event/server_events.c index 023e8a13..f6c640f3 100644 --- a/src/event/server_events.c +++ b/src/event/server_events.c @@ -260,7 +260,7 @@ sv_ev_room_history(const char *const room_jid, const char *const nick, } void -sv_ev_room_message(const char *const room_jid, const char *const nick, const char *const message, gboolean omemo) +sv_ev_room_message(const char *const room_jid, const char *const nick, const char *const message, const char *const id, gboolean omemo) { ProfMucWin *mucwin = wins_get_muc(room_jid); if (!mucwin) { @@ -268,10 +268,6 @@ sv_ev_room_message(const char *const room_jid, const char *const nick, const cha } char *mynick = muc_nick(mucwin->roomjid); - if (g_strcmp0(mynick, nick) == 0) { - /* Ignore message reflection */ - return; - } if (omemo) { groupchat_log_omemo_msg_in(room_jid, nick, message); @@ -295,9 +291,9 @@ sv_ev_room_message(const char *const room_jid, const char *const nick, const cha GList *triggers = prefs_message_get_triggers(new_message); if (omemo) { - mucwin_incoming_msg(mucwin, nick, new_message, mentions, triggers, PROF_MSG_OMEMO); + mucwin_incoming_msg(mucwin, nick, new_message, id, mentions, triggers, PROF_MSG_OMEMO); } else { - mucwin_incoming_msg(mucwin, nick, new_message, mentions, triggers, PROF_MSG_PLAIN); + mucwin_incoming_msg(mucwin, nick, new_message, id, mentions, triggers, PROF_MSG_PLAIN); } g_slist_free(mentions); diff --git a/src/event/server_events.h b/src/event/server_events.h index cf437f9a..713e50f5 100644 --- a/src/event/server_events.h +++ b/src/event/server_events.h @@ -48,7 +48,7 @@ void sv_ev_room_subject(const char *const room, const char *const nick, const ch void sv_ev_room_history(const char *const room_jid, const char *const nick, GDateTime *timestamp, const char *const message, gboolean omemo); void sv_ev_room_message(const char *const room_jid, const char *const nick, - const char *const message, gboolean omemo); + const char *const message, const char *const id, gboolean omemo); void sv_ev_incoming_message(char *barejid, char *resource, char *message, char *pgp_message, GDateTime *timestamp, gboolean omemo); void sv_ev_incoming_private_message(const char *const fulljid, char *message); void sv_ev_delayed_private_message(const char *const fulljid, char *message, GDateTime *timestamp); diff --git a/src/ui/mucwin.c b/src/ui/mucwin.c index abbcd21c..0122950a 100644 --- a/src/ui/mucwin.c +++ b/src/ui/mucwin.c @@ -478,10 +478,12 @@ _mucwin_print_triggers(ProfWin *window, const char *const message, GList *trigge } void -mucwin_outgoing_msg(ProfMucWin *mucwin, const char *const message, prof_enc_t enc_mode) +mucwin_outgoing_msg(ProfMucWin *mucwin, const char *const message, const char *const id, prof_enc_t enc_mode) { assert(mucwin != NULL); + g_hash_table_insert(mucwin->sent_messages, strdup(id), NULL); + ProfWin *window = (ProfWin*)mucwin; char *mynick = muc_nick(mucwin->roomjid); @@ -500,10 +502,15 @@ mucwin_outgoing_msg(ProfMucWin *mucwin, const char *const message, prof_enc_t en } void -mucwin_incoming_msg(ProfMucWin *mucwin, const char *const nick, const char *const message, GSList *mentions, GList *triggers, prof_enc_t enc_mode) +mucwin_incoming_msg(ProfMucWin *mucwin, const char *const nick, const char *const message, const char *const id, GSList *mentions, GList *triggers, prof_enc_t enc_mode) { assert(mucwin != NULL); + if (g_hash_table_remove(mucwin->sent_messages, id)) { + /* Ignore reflection messages */ + return; + } + ProfWin *window = (ProfWin*)mucwin; char *mynick = muc_nick(mucwin->roomjid); diff --git a/src/ui/ui.h b/src/ui/ui.h index 79701a27..b94fe475 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -162,8 +162,8 @@ void mucwin_occupant_role_and_affiliation_change(ProfMucWin *mucwin, const char const char *const role, const char *const affiliation, const char *const actor, const char *const reason); void mucwin_roster(ProfMucWin *mucwin, GList *occupants, const char *const presence); void mucwin_history(ProfMucWin *mucwin, const char *const nick, GDateTime *timestamp, const char *const message); -void mucwin_outgoing_msg(ProfMucWin *mucwin, const char *const message, prof_enc_t enc_mode); -void mucwin_incoming_msg(ProfMucWin *mucwin, const char *const nick, const char *const message, GSList *mentions, GList *triggers, prof_enc_t enc_mode); +void mucwin_outgoing_msg(ProfMucWin *mucwin, const char *const message, const char *const id, prof_enc_t enc_mode); +void mucwin_incoming_msg(ProfMucWin *mucwin, const char *const nick, const char *const message, const char *const id, GSList *mentions, GList *triggers, prof_enc_t enc_mode); void mucwin_subject(ProfMucWin *mucwin, const char *const nick, const char *const subject); void mucwin_requires_config(ProfMucWin *mucwin); void mucwin_info(ProfMucWin *mucwin); diff --git a/src/ui/win_types.h b/src/ui/win_types.h index 498d9bbe..e1e64bf9 100644 --- a/src/ui/win_types.h +++ b/src/ui/win_types.h @@ -172,6 +172,7 @@ typedef struct prof_muc_win_t { unsigned long memcheck; char *enctext; char *message_char; + GHashTable *sent_messages; } ProfMucWin; typedef struct prof_conf_win_t ProfConfWin; diff --git a/src/ui/window.c b/src/ui/window.c index 64b04365..12b6c15b 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -198,6 +198,7 @@ win_create_muc(const char *const roomjid) new_win->enctext = NULL; new_win->message_char = NULL; new_win->is_omemo = FALSE; + new_win->sent_messages = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL); new_win->memcheck = PROFMUCWIN_MEMCHECK; diff --git a/src/ui/window_list.c b/src/ui/window_list.c index 5ce68d63..43230b57 100644 --- a/src/ui/window_list.c +++ b/src/ui/window_list.c @@ -561,6 +561,7 @@ wins_close_by_num(int i) ProfMucWin *mucwin = (ProfMucWin*)window; autocomplete_remove(wins_ac, mucwin->roomjid); autocomplete_remove(wins_close_ac, mucwin->roomjid); + g_hash_table_remove_all(mucwin->sent_messages); break; } case WIN_PRIVATE: diff --git a/src/xmpp/message.c b/src/xmpp/message.c index 2a6ad234..47cf35d7 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -326,6 +326,7 @@ message_send_chat_omemo(const char *const jid, uint32_t sid, GList *keys, if (muc) { id = connection_create_stanza_id("muc"); message = xmpp_message_new(ctx, STANZA_TYPE_GROUPCHAT, jid, id); + stanza_attach_origin_id(ctx, message, id); } else { id = connection_create_stanza_id("msg"); message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id); @@ -442,23 +443,24 @@ message_send_private(const char *const fulljid, const char *const msg, const cha xmpp_stanza_release(message); } -void +char* message_send_groupchat(const char *const roomjid, const char *const msg, const char *const oob_url) { xmpp_ctx_t * const ctx = connection_get_ctx(); char *id = connection_create_stanza_id("muc"); xmpp_stanza_t *message = xmpp_message_new(ctx, STANZA_TYPE_GROUPCHAT, roomjid, id); + stanza_attach_origin_id(ctx, message, id); xmpp_message_set_body(message, msg); - free(id); - if (oob_url) { stanza_attach_x_oob_url(ctx, message, oob_url); } _send_message_stanza(message); xmpp_stanza_release(message); + + return id; } void @@ -687,6 +689,14 @@ _handle_groupchat(xmpp_stanza_t *const stanza) { xmpp_ctx_t *ctx = connection_get_ctx(); char *message = NULL; + + const char *id = xmpp_stanza_get_id(stanza); + + xmpp_stanza_t *origin = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_STABLE_ID); + if (origin && g_strcmp0(xmpp_stanza_get_name(origin), STANZA_NAME_ORIGIN_ID) == 0) { + id = xmpp_stanza_get_attribute(origin, STANZA_ATTR_ID); + } + const char *room_jid = xmpp_stanza_get_from(stanza); Jid *jid = jid_create(room_jid); @@ -750,7 +760,7 @@ _handle_groupchat(xmpp_stanza_t *const stanza) sv_ev_room_history(jid->barejid, jid->resourcepart, timestamp, message, omemo); g_date_time_unref(timestamp); } else { - sv_ev_room_message(jid->barejid, jid->resourcepart, message, omemo); + sv_ev_room_message(jid->barejid, jid->resourcepart, message, id, omemo); } xmpp_free(ctx, message); diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index f4fd8aa8..615de44f 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -2417,6 +2417,21 @@ stanza_create_pubsub_configure_submit(xmpp_ctx_t *ctx, const char *const id, con return iq; } +xmpp_stanza_t* +stanza_attach_origin_id(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char *const id) +{ + xmpp_stanza_t *origin_id = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(origin_id, STANZA_NAME_ORIGIN_ID); + xmpp_stanza_set_ns(origin_id, STANZA_NS_STABLE_ID); + xmpp_stanza_set_attribute(origin_id, STANZA_ATTR_ID, id); + + xmpp_stanza_add_child(stanza, origin_id); + + xmpp_stanza_release(origin_id); + + return stanza; +} + static void _stanza_add_unique_id(xmpp_stanza_t *stanza, char *prefix) { diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index eaf76a27..e5e17ba4 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -102,6 +102,7 @@ #define STANZA_NAME_URL "url" #define STANZA_NAME_COMMAND "command" #define STANZA_NAME_CONFIGURE "configure" +#define STANZA_NAME_ORIGIN_ID "origin-id" // error conditions #define STANZA_NAME_BAD_REQUEST "bad-request" @@ -196,6 +197,7 @@ #define STANZA_NS_OMEMO "eu.siacs.conversations.axolotl" #define STANZA_NS_OMEMO_DEVICELIST "eu.siacs.conversations.axolotl.devicelist" #define STANZA_NS_OMEMO_BUNDLES "eu.siacs.conversations.axolotl.bundles" +#define STANZA_NS_STABLE_ID "urn:xmpp:sid:0" #define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo" @@ -238,6 +240,7 @@ xmpp_stanza_t* stanza_attach_hints_no_store(xmpp_ctx_t *ctx, xmpp_stanza_t *stan xmpp_stanza_t* stanza_attach_hints_store(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza); xmpp_stanza_t* stanza_attach_receipt_request(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza); xmpp_stanza_t* stanza_attach_x_oob_url(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char *const url); +xmpp_stanza_t* stanza_attach_origin_id(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char *const id); xmpp_stanza_t* stanza_create_room_join_presence(xmpp_ctx_t *const ctx, const char *const full_room_jid, const char *const passwd); diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 39877bc2..54a56f02 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -144,7 +144,7 @@ char* message_send_chat_otr(const char *const barejid, const char *const msg, gb char* message_send_chat_pgp(const char *const barejid, const char *const msg, gboolean request_receipt); char* message_send_chat_omemo(const char *const jid, uint32_t sid, GList *keys, const unsigned char *const iv, size_t iv_len, const unsigned char *const ciphertext, size_t ciphertext_len, gboolean request_receipt, gboolean muc); void message_send_private(const char *const fulljid, const char *const msg, const char *const oob_url); -void message_send_groupchat(const char *const roomjid, const char *const msg, const char *const oob_url); +char* message_send_groupchat(const char *const roomjid, const char *const msg, const char *const oob_url); void message_send_groupchat_subject(const char *const roomjid, const char *const subject); void message_send_inactive(const char *const jid); void message_send_composing(const char *const jid); diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c index 950036bc..361a42e2 100644 --- a/tests/unittests/ui/stub_ui.c +++ b/tests/unittests/ui/stub_ui.c @@ -190,8 +190,8 @@ void mucwin_occupant_role_and_affiliation_change(ProfMucWin *mucwin, const char const char * const affiliation, const char * const actor, const char * const reason) {} void mucwin_roster(ProfMucWin *mucwin, GList *occupants, const char * const presence) {} void mucwin_history(ProfMucWin *mucwin, const char * const nick, GDateTime *timestamp, const char * const message) {} -void mucwin_incoming_msg(ProfMucWin *mucwin, const char *const nick, const char *const message, GSList *mentions, GList *triggers, prof_enc_t enc_mode) {} -void mucwin_outgoing_msg(ProfMucWin *mucwin, const char *const message, prof_enc_t enc_mode) {} +void mucwin_incoming_msg(ProfMucWin *mucwin, const char *const nick, const char *const message, const char *const id, GSList *mentions, GList *triggers, prof_enc_t enc_mode) {} +void mucwin_outgoing_msg(ProfMucWin *mucwin, const char *const message, const char *const id, prof_enc_t enc_mode) {} void mucwin_subject(ProfMucWin *mucwin, const char * const nick, const char * const subject) {} void mucwin_requires_config(ProfMucWin *mucwin) {} void ui_room_destroy(const char * const roomjid) {} diff --git a/tests/unittests/xmpp/stub_xmpp.c b/tests/unittests/xmpp/stub_xmpp.c index bc2c50db..53a729e6 100644 --- a/tests/unittests/xmpp/stub_xmpp.c +++ b/tests/unittests/xmpp/stub_xmpp.c @@ -114,7 +114,10 @@ char* message_send_chat_pgp(const char * const barejid, const char * const msg, } void message_send_private(const char * const fulljid, const char * const msg, const char *const oob_url) {} -void message_send_groupchat(const char * const roomjid, const char * const msg, const char *const oob_url) {} +char* message_send_groupchat(const char * const roomjid, const char * const msg, const char *const oob_url) +{ + return NULL; +} void message_send_groupchat_subject(const char * const roomjid, const char * const subject) {} void message_send_inactive(const char * const barejid) {} -- cgit 1.4.1-2-gfad0