From 5eca4ac37cb207c4989a9259c1be0ccb203439d6 Mon Sep 17 00:00:00 2001 From: Tony Olagbaiye Date: Thu, 29 Jul 2021 04:06:48 +0100 Subject: [PATCH] omemo progress++ --- .envrc | 2 +- README.org | 8 + account.c | 93 +++++++ account.h | 24 ++ channel.c | 74 +++++- channel.h | 2 +- command.c | 2 +- config.c | 29 +- connection.c | 46 +++- omemo.c | 740 +++++++++++++++++++++++++++++++++++++++++++-------- omemo.h | 5 +- pgp.c | 17 +- pgp.h | 2 +- user.c | 6 +- user.h | 2 +- 15 files changed, 908 insertions(+), 144 deletions(-) diff --git a/.envrc b/.envrc index f2874d4..aeb2bc0 100644 --- a/.envrc +++ b/.envrc @@ -40,7 +40,7 @@ use_guix() libtool # Deps with libtool make # Makefile and deps with makefiles cmake # Deps with cmake - gcc-toolchain # Compilation + gcc-toolchain@11 # Compilation pkg-config # Deps configuration and configuration of deps deps patchelf # Fix linkage (guix) bear # Generate compile_commands.json for language servers diff --git a/README.org b/README.org index d4815c5..200c7c1 100644 --- a/README.org +++ b/README.org @@ -28,6 +28,9 @@ A weechat plugin in C to extend the chat client to support XMPP and a currently minimal but ideally maximal set of XEPs. + My priority here is to have an android-available XMPP client + that hides as little as possible from the user. To use this with + android, set up a relay (`/relay`) and see weechat-android. I'm gonna rewrite this in C++ at some point when I have a feel for the full behaviour of an average client. @@ -132,6 +135,11 @@ * [X] [#A] Recv typing notifications * [X] [#C] Read receipts * [X] Chat Markers (XEP-0333) + * [X] Composing + * [X] Paused + * [?] Active + * [ ] Inactive + * [ ] Gone * [X] Message Delivery (XEP-0184) * [X] Message Carbons * [ ] Service Disco diff --git a/account.c b/account.c index ab4464c..d6a449e 100644 --- a/account.c +++ b/account.c @@ -165,6 +165,95 @@ void account__free_device_all(struct t_account *account) account__free_device(account, account->devices); } +struct t_account_mam_query *account__add_mam_query(struct t_account *account, + struct t_channel *channel, + const char *id, + time_t *start, time_t *end) +{ + struct t_account_mam_query *mam_query; + + if (!(mam_query = account__mam_query_search(account, id))) + { + mam_query = malloc(sizeof(struct t_account_mam_query)); + mam_query->id = strdup(id); + mam_query->with = strdup(channel->id); + + mam_query->has_start = start != NULL; + if (mam_query->has_start) + mam_query->start = *start; + mam_query->has_end = end != NULL; + if (mam_query->has_end) + mam_query->end = *end; + + mam_query->prev_mam_query = account->last_mam_query; + mam_query->next_mam_query = NULL; + if (account->last_mam_query) + (account->last_mam_query)->next_mam_query = mam_query; + else + account->mam_queries = mam_query; + account->last_mam_query = mam_query; + } + + return mam_query; +} + +struct t_account_mam_query *account__mam_query_search(struct t_account *account, + const char *id) +{ + struct t_account_mam_query *ptr_mam_query; + + if (!account || !id) + return NULL; + + for (ptr_mam_query = account->mam_queries; ptr_mam_query; + ptr_mam_query = ptr_mam_query->next_mam_query) + { + if (weechat_strcasecmp(ptr_mam_query->id, id) == 0) + return ptr_mam_query; + } + + return NULL; +} + +void account__mam_query_free(struct t_account *account, + struct t_account_mam_query *mam_query) +{ + struct t_account_mam_query *new_mam_queries; + + if (!account || !mam_query) + return; + + /* remove mam_query from mam_queries list */ + if (account->last_mam_query == mam_query) + account->last_mam_query = mam_query->prev_mam_query; + if (mam_query->prev_mam_query) + { + (mam_query->prev_mam_query)->next_mam_query = mam_query->next_mam_query; + new_mam_queries = account->mam_queries; + } + else + new_mam_queries = mam_query->next_mam_query; + + if (mam_query->next_mam_query) + (mam_query->next_mam_query)->prev_mam_query = mam_query->prev_mam_query; + + /* free mam_query data */ + if (mam_query->id) + free(mam_query->id); + if (mam_query->with) + free(mam_query->with); + + free(mam_query); + + account->mam_queries = new_mam_queries; +} + +void account__mam_query_free_all(struct t_account *account) +{ + while (account->mam_queries) + account__mam_query_free(account, account->mam_queries); +} + void account__log_emit_weechat(void *const userdata, const xmpp_log_level_t level, const char *const area, const char *const msg) { @@ -304,6 +393,8 @@ struct t_account *account__alloc(const char *name) new_account->devices = NULL; new_account->last_device = NULL; + new_account->mam_queries = NULL; + new_account->last_mam_query = NULL; new_account->users = NULL; new_account->last_user = NULL; new_account->channels = NULL; @@ -364,6 +455,8 @@ void account__free_data(struct t_account *account) xmpp_redirect_free_all(account); xmpp_notify_free_all(account); */ + account__free_device_all(account); + account__mam_query_free_all(account); channel__free_all(account); user__free_all(account); diff --git a/account.h b/account.h index 575996f..4234749 100644 --- a/account.h +++ b/account.h @@ -73,6 +73,19 @@ struct t_account_device struct t_account_device *next_device; }; +struct t_account_mam_query +{ + char *id; + char *with; + int has_start; + time_t start; + int has_end; + time_t end; + + struct t_account_mam_query *prev_mam_query; + struct t_account_mam_query *next_mam_query; +}; + struct t_account { char *name; @@ -99,6 +112,8 @@ struct t_account struct t_account_device *devices; struct t_account_device *last_device; + struct t_account_mam_query *mam_queries; + struct t_account_mam_query *last_mam_query; struct t_user *users; struct t_user *last_user; struct t_channel *channels; @@ -117,6 +132,15 @@ struct t_account_device *account__search_device(struct t_account *account, int i void account__add_device(struct t_account *account, struct t_account_device *device); void account__free_device(struct t_account *account, struct t_account_device *device); void account__free_device_all(struct t_account *account); +struct t_account_mam_query *account__add_mam_query(struct t_account *account, + struct t_channel *channel, + const char *id, + time_t *start, time_t *end); +struct t_account_mam_query *account__mam_query_search(struct t_account *account, + const char *id); +void account__mam_query_free(struct t_account *account, + struct t_account_mam_query *mam_query); +void account__mam_query_free_all(struct t_account *account); struct t_account *account__alloc(const char *name); void account__free_data(struct t_account *account); void account__free(struct t_account *account); diff --git a/channel.c b/channel.c index a60b21f..8577aae 100644 --- a/channel.c +++ b/channel.c @@ -314,7 +314,7 @@ struct t_channel *channel__new(struct t_account *account, struct tm *ago = gmtime(&start); ago->tm_mday -= 7; start = mktime(ago); - channel__fetch_mam(account, new_channel, &start, NULL); + channel__fetch_mam(account, new_channel, NULL, &start, NULL, NULL); } return new_channel; @@ -886,7 +886,7 @@ struct t_channel_member *channel__add_member(struct t_account *account, client ? ")" : "", user->profile.status ? "is " : "", weechat_color("irc.color.message_join"), - user->profile.status ? user->profile.status : "entered", + user->profile.status ? user->profile.status : (user->profile.idle ? "idle" : "entered"), weechat_color("reset"), channel->id, user->profile.status_text ? " [" : "", @@ -901,15 +901,16 @@ struct t_channel_member *channel__add_member(struct t_account *account, user->profile.pgp_id ? user->profile.pgp_id : "", user->profile.pgp_id ? weechat_color("reset") : ""); else - weechat_printf_date_tags(channel->buffer, 0, "xmpp_presence,enter,log4", "%s%s (%s) %s%s%s%s %s%s%s%s%s%s%s%s", + weechat_printf_date_tags(channel->buffer, 0, "xmpp_presence,enter,log4", "%s%s (%s) %s%s%s%s %s%s%s%s%s%s%s%s%s", weechat_prefix("join"), jid_resource ? user__as_prefix_raw(account, jid_bare) : "You", jid_resource ? jid_resource : user__as_prefix_raw(account, jid_bare), user->profile.status ? "is " : "", weechat_color("irc.color.message_join"), - user->profile.status ? user->profile.status : "entered", + user->profile.status ? user->profile.status : (user->profile.idle ? "idle" : "entered"), weechat_color("reset"), - channel->id, + user->profile.idle ? "since " : "", + user->profile.idle ? user->profile.idle : "", user->profile.status_text ? " [" : "", user->profile.status_text ? user->profile.status_text : "", user->profile.status_text ? "]" : "", @@ -996,8 +997,6 @@ void channel__send_message(struct t_account *account, struct t_channel *channel, xmpp_stanza_set_id(message, id); xmpp_free(account->context, id); - xmpp_message_set_body(message, body); - char *url = strstr(body, "http"); if (channel->pgp_id) { @@ -1006,7 +1005,7 @@ void channel__send_message(struct t_account *account, struct t_channel *channel, xmpp_stanza_set_ns(message__x, "jabber:x:encrypted"); xmpp_stanza_t *message__x__text = xmpp_stanza_new(account->context); - char *ciphertext = pgp__encrypt(channel->buffer, account->pgp, channel->pgp_id, body); + char *ciphertext = pgp__encrypt(channel->buffer, account->pgp, account_pgp_keyid(account), channel->pgp_id, body); if (ciphertext) xmpp_stanza_set_text(message__x__text, ciphertext); free(ciphertext); @@ -1017,6 +1016,14 @@ void channel__send_message(struct t_account *account, struct t_channel *channel, xmpp_stanza_add_child(message, message__x); xmpp_stanza_release(message__x); + xmpp_stanza_t *message__encryption = xmpp_stanza_new(account->context); + xmpp_stanza_set_name(message__encryption, "encryption"); + xmpp_stanza_set_ns(message__encryption, "urn:xmpp:eme:0"); + xmpp_stanza_set_attribute(message__encryption, "namespace", "jabber:x:encryption"); + + xmpp_stanza_add_child(message, message__encryption); + xmpp_stanza_release(message__encryption); + xmpp_message_set_body(message, PGP_ADVICE); if (ciphertext && channel->transport != CHANNEL_TRANSPORT_PGP) @@ -1027,12 +1034,17 @@ void channel__send_message(struct t_account *account, struct t_channel *channel, channel__transport_name(channel->transport)); } } - else if (channel->transport != CHANNEL_TRANSPORT_PLAINTEXT) + else { - channel->transport = CHANNEL_TRANSPORT_PLAINTEXT; - weechat_printf_date_tags(channel->buffer, 0, NULL, "%s%sTransport: %s", - weechat_prefix("network"), weechat_color("gray"), - channel__transport_name(channel->transport)); + xmpp_message_set_body(message, body); + + if (channel->transport != CHANNEL_TRANSPORT_PLAINTEXT) + { + channel->transport = CHANNEL_TRANSPORT_PLAINTEXT; + weechat_printf_date_tags(channel->buffer, 0, NULL, "%s%sTransport: %s", + weechat_prefix("network"), weechat_color("gray"), + channel__transport_name(channel->transport)); + } } if (url) @@ -1056,6 +1068,13 @@ void channel__send_message(struct t_account *account, struct t_channel *channel, xmpp_stanza_release(message__x); } + xmpp_stanza_t *message__active = xmpp_stanza_new(account->context); + xmpp_stanza_set_name(message__active, "active"); + xmpp_stanza_set_ns(message__active, "http://jabber./org/protocol/chatstates"); + + xmpp_stanza_add_child(message, message__active); + xmpp_stanza_release(message__active); + xmpp_send(account->connection, message); xmpp_stanza_release(message); if (channel->type != CHANNEL_TYPE_MUC) @@ -1157,9 +1176,10 @@ void channel__send_paused(struct t_account *account, struct t_channel *channel, } void channel__fetch_mam(struct t_account *account, struct t_channel *channel, - time_t *start, time_t *end) + const char *id, time_t *start, time_t *end, const char* after) { xmpp_stanza_t *iq = xmpp_iq_new(account->context, "set", "juliet1"); + xmpp_stanza_set_id(iq, id ? id : xmpp_uuid_gen(account->context)); xmpp_stanza_t *query = xmpp_stanza_new(account->context); xmpp_stanza_set_name(query, "query"); @@ -1262,6 +1282,32 @@ void channel__fetch_mam(struct t_account *account, struct t_channel *channel, xmpp_stanza_add_child(query, x); xmpp_stanza_release(x); + if (after) + { + xmpp_stanza_t *set, *set__after, *set__after__text; + + set = xmpp_stanza_new(account->context); + xmpp_stanza_set_name(set, "set"); + xmpp_stanza_set_ns(set, "http://jabber.org/protocol/rsm"); + + set__after = xmpp_stanza_new(account->context); + xmpp_stanza_set_name(set__after, "after"); + + set__after__text = xmpp_stanza_new(account->context); + xmpp_stanza_set_text(set__after__text, after); + xmpp_stanza_add_child(set__after, set__after__text); + xmpp_stanza_release(set__after__text); + + xmpp_stanza_add_child(set, set__after); + xmpp_stanza_release(set__after); + + xmpp_stanza_add_child(query, set); + xmpp_stanza_release(set); + } + else + account__add_mam_query(account, channel, + xmpp_stanza_get_id(iq), start, end); + xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); diff --git a/channel.h b/channel.h index c336ee2..37863f1 100644 --- a/channel.h +++ b/channel.h @@ -191,6 +191,6 @@ void channel__send_paused(struct t_account *account, struct t_channel *channel, struct t_user *user); void channel__fetch_mam(struct t_account *account, struct t_channel *channel, - time_t *start, time_t *end); + const char *id, time_t *start, time_t *end, const char *after); #endif /*WEECHAT_XMPP_CHANNEL_H*/ diff --git a/command.c b/command.c index 84c90ed..57c7019 100644 --- a/command.c +++ b/command.c @@ -752,7 +752,7 @@ int command__mam(const void *pointer, void *data, else ago->tm_mday -= MAM_DEFAULT_DAYS; start = mktime(ago); - channel__fetch_mam(ptr_account, ptr_channel, &start, NULL); + channel__fetch_mam(ptr_account, ptr_channel, NULL, &start, NULL, NULL); return WEECHAT_RC_OK; } diff --git a/config.c b/config.c index 0686d10..fc89b78 100644 --- a/config.c +++ b/config.c @@ -21,8 +21,8 @@ struct t_config_option *config_look_nick_completion_smart; struct t_config_option *config_account_default[ACCOUNT_NUM_OPTIONS]; int config__account_check_value_cb(const void *pointer, void *data, - struct t_config_option *option, - const char *value) + struct t_config_option *option, + const char *value) { (void) pointer; (void) data; @@ -33,15 +33,32 @@ int config__account_check_value_cb(const void *pointer, void *data, } void config__account_change_cb(const void *pointer, void *data, - struct t_config_option *option) + struct t_config_option *option) { (void) pointer; (void) data; - (void) option; + + const char *name = + weechat_config_option_get_string(option, "name"); + const char *value = + weechat_config_option_get_string(option, "value"); + + int split_num; + char **split = weechat_string_split(name, ".", NULL, 0, 2, &split_num); + struct t_account *account = account__search(split[0]); + if (split_num >= 2 && account) + { + const char *key = split[1]; + + (void) key; + (void) value; + } + + weechat_string_free_split(split); } void config__account_default_change_cb(const void *pointer, void *data, - struct t_config_option *option) + struct t_config_option *option) { (void) pointer; (void) data; @@ -346,7 +363,7 @@ int config__account_read_cb (const void *pointer, void *data, return rc; } -int config__account_write_cb (const void *pointer, void *data, +int config__account_write_cb(const void *pointer, void *data, struct t_config_file *config_file, const char *section_name) { diff --git a/connection.c b/connection.c index afb0683..16b5dbb 100644 --- a/connection.c +++ b/connection.c @@ -86,9 +86,9 @@ int connection__presence_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void struct t_account *account = (struct t_account *)userdata; struct t_user *user; struct t_channel *channel; - xmpp_stanza_t *iq__x_signed, *iq__x_muc_user, *show, *iq__x__item, *iq__c, *iq__status; + xmpp_stanza_t *iq__x_signed, *iq__x_muc_user, *show, *idle, *iq__x__item, *iq__c, *iq__status; const char *from, *from_bare, *from_res, *type, *role = NULL, *affiliation = NULL, *jid = NULL; - const char *show__text = NULL, *certificate = NULL, *node = NULL, *ver = NULL; + const char *show__text = NULL, *idle__since = NULL, *certificate = NULL, *node = NULL, *ver = NULL; char *clientid = NULL, *status; from = xmpp_stanza_get_from(stanza); @@ -99,6 +99,8 @@ int connection__presence_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void type = xmpp_stanza_get_type(stanza); show = xmpp_stanza_get_child_by_name(stanza, "show"); show__text = show ? xmpp_stanza_get_text(show) : NULL; + idle = xmpp_stanza_get_child_by_name_and_ns(stanza, "idle", "urn:xmpp:idle:1"); + idle__since = idle ? xmpp_stanza_get_attribute(idle, "since") : NULL; iq__x_signed = xmpp_stanza_get_child_by_name_and_ns( stanza, "x", "jabber:x:signed"); if (iq__x_signed) @@ -145,6 +147,7 @@ int connection__presence_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void ? from_res : from); user->profile.status_text = status ? strdup(status) : NULL; user->profile.status = show ? strdup(show__text) : NULL; + user->profile.idle = idle ? strdup(idle__since) : NULL; user->is_away = show ? weechat_strcasecmp(show__text, "away") == 0 : 0; user->profile.role = role ? strdup(role) : NULL; user->profile.affiliation = affiliation && strcmp(affiliation, "none") != 0 @@ -173,6 +176,8 @@ int connection__presence_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void ? from_res : from); user->profile.status_text = status ? strdup(status) : NULL; user->profile.status = show ? strdup(show__text) : NULL; + user->profile.idle = idle ? strdup(idle__since) : NULL; + user->is_away = show ? weechat_strcasecmp(show__text, "away") == 0 : 0; user->profile.role = role ? strdup(role) : NULL; user->profile.affiliation = affiliation && strcmp(affiliation, "none") != 0 ? strdup(affiliation) : NULL; @@ -602,14 +607,13 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void * int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) { - (void) conn; - struct t_account *account = (struct t_account *)userdata; - xmpp_stanza_t *reply, *query, *identity, *feature, *x, *field, *value, *text; + xmpp_stanza_t *reply, *query, *identity, *feature, *x, *field, *value, *text, *fin; xmpp_stanza_t *pubsub, *items, *item, *list, *device, **children; xmpp_stanza_t *storage, *conference, *nick; static struct utsname osinfo; + const char *id = xmpp_stanza_get_id(stanza); query = xmpp_stanza_get_child_by_name_and_ns( stanza, "query", "http://jabber.org/protocol/disco#info"); const char *type = xmpp_stanza_get_attribute(stanza, "type"); @@ -1023,6 +1027,38 @@ int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userd } } + fin = xmpp_stanza_get_child_by_name_and_ns( + stanza, "fin", "urn:xmpp:mam:2"); + if (fin) + { + xmpp_stanza_t *set, *set__last; + char *set__last__text; + struct t_account_mam_query *mam_query; + + set = xmpp_stanza_get_child_by_name_and_ns( + fin, "set", "http://jabber.org/protocol/rsm"); + mam_query = account__mam_query_search(account, id); + if (set && mam_query) + { + struct t_channel *channel = channel__search(account, + mam_query->with); + + set__last = xmpp_stanza_get_child_by_name(set, "last"); + set__last__text = set__last + ? xmpp_stanza_get_text(set__last) : NULL; + + if (channel && set__last__text) + { + channel__fetch_mam(account, channel, id, + mam_query->has_start ? &mam_query->start : NULL, + mam_query->has_end ? &mam_query->end : NULL, + set__last__text); + } + else if (!set__last) + account__mam_query_free(account, mam_query); + } + } + return 1; } diff --git a/omemo.c b/omemo.c index 63134cc..811a508 100644 --- a/omemo.c +++ b/omemo.c @@ -9,32 +9,36 @@ #include #include #include +#include #include #include #include +struct t_omemo_db { + MDB_env *env; + MDB_dbi dbi_omemo; +}; + #include "plugin.h" #include "account.h" #include "omemo.h" -const char *OMEMO_ADVICE = "[OMEMO encrypted message (XEP-0384)]"; +#define mdb_val_str(s) { \ + .mv_data = s, .mv_size = strlen(s), \ +} -signal_type_base* signal_type_ref_vapi(void* instance) { - if (!(instance != NULL)) - return NULL; - signal_type_ref(instance); - return instance; +#define mdb_val_intptr(i) { \ + .mv_data = i, .mv_size = sizeof(*i), \ } -signal_type_base* signal_type_unref_vapi(void* instance) { - if (!(instance != NULL)) - return NULL; - signal_type_unref(instance); - return NULL; +#define mdb_val_sizeof(t) { \ + .mv_data = NULL, .mv_size = sizeof(t), \ } +const char *OMEMO_ADVICE = "[OMEMO encrypted message (XEP-0384)]"; + void signal_protocol_address_free(signal_protocol_address* ptr) { - if (!(ptr != NULL)) + if (!ptr) return; if (ptr->name) { free((void*)ptr->name); @@ -43,9 +47,9 @@ void signal_protocol_address_free(signal_protocol_address* ptr) { } void signal_protocol_address_set_name(signal_protocol_address* self, const char* name) { - if (!(self != NULL)) + if (!self) return; - if (!(name != NULL)) + if (!name) return; char* n = malloc(strlen(name)+1); memcpy(n, name, strlen(name)); @@ -58,9 +62,9 @@ void signal_protocol_address_set_name(signal_protocol_address* self, const char* } char* signal_protocol_address_get_name(signal_protocol_address* self) { - if (!(self != NULL)) + if (!self) return NULL; - if (!(self->name != NULL)) + if (!self->name) return 0; char* res = malloc(sizeof(char) * (self->name_len + 1)); memcpy(res, self->name, self->name_len); @@ -69,19 +73,19 @@ char* signal_protocol_address_get_name(signal_protocol_address* self) { } int32_t signal_protocol_address_get_device_id(signal_protocol_address* self) { - if (!(self != NULL)) + if (!self) return -1; return self->device_id; } void signal_protocol_address_set_device_id(signal_protocol_address* self, int32_t device_id) { - if (!(self != NULL)) + if (!self) return; self->device_id = device_id; } signal_protocol_address* signal_protocol_address_new(const char* name, int32_t device_id) { - if (!(name != NULL)) + if (!name) return NULL; signal_protocol_address* address = malloc(sizeof(signal_protocol_address)); address->device_id = -1; @@ -91,6 +95,43 @@ signal_protocol_address* signal_protocol_address_new(const char* name, int32_t d return address; } +int aes_cipher(int cipher, size_t key_len, int* algo, int* mode) { + switch (key_len) { + case 16: + *algo = GCRY_CIPHER_AES128; + break; + case 24: + *algo = GCRY_CIPHER_AES192; + break; + case 32: + *algo = GCRY_CIPHER_AES256; + break; + default: + return SG_ERR_UNKNOWN; + } + switch (cipher) { + case SG_CIPHER_AES_CBC_PKCS5: + *mode = GCRY_CIPHER_MODE_CBC; + break; + case SG_CIPHER_AES_CTR_NOPADDING: + *mode = GCRY_CIPHER_MODE_CTR; + break; + default: + return SG_ERR_UNKNOWN; + } + return SG_SUCCESS; +} + +void lock_function(void *user_data) +{ + (void) user_data; +} + +void unlock_function(void *user_data) +{ + (void) user_data; +} + int cp_randomize(uint8_t *data, size_t len) { gcry_randomize(data, len, GCRY_STRONG_RANDOM); return SG_SUCCESS; @@ -217,33 +258,6 @@ void cp_sha512_digest_cleanup(void *digest_context, void *user_data) { } } -int aes_cipher(int cipher, size_t key_len, int* algo, int* mode) { - switch (key_len) { - case 16: - *algo = GCRY_CIPHER_AES128; - break; - case 24: - *algo = GCRY_CIPHER_AES192; - break; - case 32: - *algo = GCRY_CIPHER_AES256; - break; - default: - return SG_ERR_UNKNOWN; - } - switch (cipher) { - case SG_CIPHER_AES_CBC_PKCS5: - *mode = GCRY_CIPHER_MODE_CBC; - break; - case SG_CIPHER_AES_CTR_NOPADDING: - *mode = GCRY_CIPHER_MODE_CTR; - break; - default: - return SG_ERR_UNKNOWN; - } - return SG_SUCCESS; -} - int cp_encrypt(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, @@ -391,70 +405,548 @@ no_error: return SG_SUCCESS; } -void lock_function(void *user_data) +int iks_get_identity_key_pair(signal_buffer **public_data, signal_buffer **private_data, void *user_data) +{ + struct t_omemo *omemo = (struct t_omemo *)user_data; + MDB_txn *transaction; + MDB_val k_local_private_key = mdb_val_str("local_private_key"); + MDB_val k_local_public_key = mdb_val_str("local_public_key"); + MDB_val v_local_private_key, v_local_public_key; + + // Get the local client's identity key pair + if (mdb_txn_begin(omemo->db->env, NULL, MDB_RDONLY, &transaction)) { + weechat_printf(NULL, "%sxmpp: failed to open lmdb transaction", + weechat_prefix("error")); + } + + if (mdb_get(transaction, omemo->db->dbi_omemo, + &k_local_private_key, &v_local_private_key) && + mdb_get(transaction, omemo->db->dbi_omemo, + &k_local_public_key, &v_local_public_key)) + { + *private_data = signal_buffer_create(v_local_private_key.mv_data, v_local_private_key.mv_size); + *public_data = signal_buffer_create(v_local_public_key.mv_data, v_local_public_key.mv_size); + + if (mdb_txn_commit(transaction)) { + weechat_printf(NULL, "%sxmpp: failed to write lmdb transaction", + weechat_prefix("error")); + return -1; + }; + } + else + { + struct ratchet_identity_key_pair *identity; + + mdb_txn_abort(transaction); + + if (mdb_txn_begin(omemo->db->env, NULL, 0, &transaction)) { + weechat_printf(NULL, "%sxmpp: failed to open lmdb transaction", + weechat_prefix("error")); + return -1; + } + + signal_protocol_key_helper_generate_identity_key_pair( + &identity, omemo->context); + ec_private_key *private_key = ratchet_identity_key_pair_get_private(identity); + ec_public_key *public_key = ratchet_identity_key_pair_get_public(identity); + + ec_private_key_serialize(private_data, private_key); + ec_public_key_serialize(public_data, public_key); + + v_local_private_key.mv_data = signal_buffer_data(*private_data); + v_local_private_key.mv_size = signal_buffer_len(*private_data); + v_local_public_key.mv_data = signal_buffer_data(*public_data); + v_local_public_key.mv_size = signal_buffer_len(*public_data); + + if (mdb_put(transaction, omemo->db->dbi_omemo, + &k_local_private_key, &v_local_private_key, MDB_NOOVERWRITE) && + mdb_put(transaction, omemo->db->dbi_omemo, + &k_local_public_key, &v_local_public_key, MDB_NOOVERWRITE)) + { + weechat_printf(NULL, "%sxmpp: failed to write lmdb value", + weechat_prefix("error")); + return -1; + }; + + if (mdb_txn_commit(transaction)) { + weechat_printf(NULL, "%sxmpp: failed to write lmdb transaction", + weechat_prefix("error")); + return -1; + }; + } + + return 0; +} + +int iks_get_local_registration_id(void *user_data, uint32_t *registration_id) +{ + struct t_omemo *omemo = (struct t_omemo *)user_data; + MDB_txn *transaction; + MDB_val k_local_registration_id = mdb_val_str("local_registration_id"); + MDB_val v_local_registration_id = mdb_val_sizeof(uint32_t); + + // Return the local client's registration ID + if (mdb_txn_begin(omemo->db->env, NULL, MDB_RDONLY, &transaction)) { + weechat_printf(NULL, "%sxmpp: failed to open lmdb transaction", + weechat_prefix("error")); + return -1; + } + + if (mdb_get(transaction, omemo->db->dbi_omemo, + &k_local_registration_id, + &v_local_registration_id)) + { + *registration_id = *(uint32_t*)v_local_registration_id.mv_data; + + if (mdb_txn_commit(transaction)) { + weechat_printf(NULL, "%sxmpp: failed to write lmdb transaction", + weechat_prefix("error")); + return -1; + }; + } + else + { + mdb_txn_abort(transaction); + + if (mdb_txn_begin(omemo->db->env, NULL, 0, &transaction)) { + weechat_printf(NULL, "%sxmpp: failed to open lmdb transaction", + weechat_prefix("error")); + return -1; + } + + signal_protocol_key_helper_generate_registration_id( + (uint32_t*)&v_local_registration_id.mv_data, 0, omemo->context); + + if (mdb_put(transaction, omemo->db->dbi_omemo, + &k_local_registration_id, + &v_local_registration_id, MDB_NOOVERWRITE)) + { + weechat_printf(NULL, "%sxmpp: failed to write lmdb value", + weechat_prefix("error")); + return -1; + }; + + if (mdb_txn_commit(transaction)) { + weechat_printf(NULL, "%sxmpp: failed to write lmdb transaction", + weechat_prefix("error")); + return -1; + }; + } + + return 0; +} + +int iks_save_identity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data) +{ + struct t_omemo *omemo = (struct t_omemo *)user_data; + MDB_txn *transaction; + MDB_val k_registration_id = { + .mv_data = NULL, + .mv_size = strlen("registration_id_") + address->name_len, + }; + MDB_val v_registration_id = mdb_val_intptr((uint32_t*)&address->device_id); + MDB_val k_identity_key = { + .mv_data = NULL, + .mv_size = strlen("identity_key_") + address->name_len, + }; + MDB_val v_identity_key = {.mv_data = key_data, .mv_size = key_len}; + + k_registration_id.mv_data = malloc(sizeof(char) * ( + k_registration_id.mv_size + 1)); + snprintf(k_registration_id.mv_data, k_registration_id.mv_size, + "registration_id_%s", address->name); + k_identity_key.mv_data = malloc(sizeof(char) * ( + k_identity_key.mv_size + 1)); + snprintf(k_identity_key.mv_data, k_identity_key.mv_size, + "identity_key_%s", address->name); + + // Save a remote client's identity key + if (mdb_txn_begin(omemo->db->env, NULL, 0, &transaction)) { + weechat_printf(NULL, "%sxmpp: failed to open lmdb transaction", + weechat_prefix("error")); + return -1; + } + + if (mdb_put(transaction, omemo->db->dbi_omemo, &k_registration_id, + &v_registration_id, 0) || + mdb_put(transaction, omemo->db->dbi_omemo, &k_identity_key, + &v_identity_key, 0)) { + weechat_printf(NULL, "%sxmpp: failed to write lmdb value", + weechat_prefix("error")); + return -1; + }; + + if (mdb_txn_commit(transaction)) { + weechat_printf(NULL, "%sxmpp: failed to write lmdb transaction", + weechat_prefix("error")); + return -1; + }; + + return 0; +} + +int iks_is_trusted_identity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data) +{ + struct t_omemo *omemo = (struct t_omemo *)user_data; + MDB_txn *transaction; + MDB_val k_registration_id = { + .mv_data = NULL, + .mv_size = strlen("registration_id_") + address->name_len, + }; + MDB_val v_registration_id = mdb_val_intptr((uint32_t*)&address->device_id); + MDB_val k_identity_key = { + .mv_data = NULL, + .mv_size = strlen("identity_key_") + address->name_len, + }; + MDB_val v_identity_key = {.mv_data = key_data, .mv_size = key_len}; + int trusted = 1; + + k_registration_id.mv_data = malloc(sizeof(char) * ( + k_registration_id.mv_size + 1)); + snprintf(k_registration_id.mv_data, k_registration_id.mv_size, + "registration_id_%s", address->name); + k_identity_key.mv_data = malloc(sizeof(char) * ( + k_identity_key.mv_size + 1)); + snprintf(k_identity_key.mv_data, k_identity_key.mv_size, + "identity_key_%s", address->name); + + // Verify a remote client's identity key + if (mdb_txn_begin(omemo->db->env, NULL, MDB_RDONLY, &transaction)) { + weechat_printf(NULL, "%sxmpp: failed to open lmdb transaction", + weechat_prefix("error")); + return -1; + } + + if (mdb_get(transaction, omemo->db->dbi_omemo, &k_registration_id, + &v_registration_id) || + mdb_get(transaction, omemo->db->dbi_omemo, &k_identity_key, + &v_identity_key)) { + weechat_printf(NULL, "%sxmpp: failed to write lmdb value", + weechat_prefix("error")); + return -1; + }; + + if (*(uint32_t*)v_registration_id.mv_data != (uint32_t)address->device_id) + trusted = 0; + if (v_identity_key.mv_size != key_len || + memcmp(v_identity_key.mv_data, key_data, key_len) != 0) + trusted = 0; + + if (mdb_txn_commit(transaction)) { + weechat_printf(NULL, "%sxmpp: failed to write lmdb transaction", + weechat_prefix("error")); + return -1; + }; + + return trusted; +} + +void iks_destroy_func(void *user_data) +{ + struct t_omemo *omemo = (struct t_omemo *)user_data; + (void) omemo; + // Function called to perform cleanup when the data store context is being destroyed +} + +int pks_load_pre_key(signal_buffer **record, uint32_t pre_key_id, void *user_data) { + struct t_omemo *omemo = (struct t_omemo *)user_data; + MDB_txn *transaction; + MDB_val k_pre_key = mdb_val_str("pre_key"); + MDB_val v_pre_key; + + if (mdb_txn_begin(omemo->db->env, NULL, MDB_RDONLY, &transaction)) { + weechat_printf(NULL, "%sxmpp: failed to open lmdb transaction", + weechat_prefix("error")); + } + + if (mdb_get(transaction, omemo->db->dbi_omemo, + &k_pre_key, &v_pre_key)) + { + *record = signal_buffer_create(v_pre_key.mv_data, v_pre_key.mv_size); + + if (mdb_txn_commit(transaction)) { + weechat_printf(NULL, "%sxmpp: failed to close lmdb transaction", + weechat_prefix("error")); + return -1; + }; + } + else + { + signal_protocol_key_helper_pre_key_list_node *pre_keys_list; + session_pre_key *pre_key = NULL; + + mdb_txn_abort(transaction); + + /* + signal_protocol_key_helper_generate_pre_keys( + &pre_keys_list, 0, 100, omemo->context); + pre_key = signal_protocol_key_helper_key_list_element(pre_keys_list); + signal_protocol_key_helper_key_list_next(pre_keys_list); + + uint32_t id = session_pre_key_get_id(pre_key); + session_pre_key_serialize(&record, pre_key); + + signal_protocol_key_helper_key_list_free(pre_keys_list); + + if (mdb_txn_begin(omemo->db->env, NULL, 0, &transaction)) { + weechat_printf(NULL, "%sxmpp: failed to open lmdb transaction", + weechat_prefix("error")); + return -1; + } + + v_pre_key.mv_data = signal_buffer_data(*record); + v_pre_key.mv_size = signal_buffer_len(*record); + + if (mdb_put(transaction, omemo->db->dbi_omemo, + &k_pre_key, &v_pre_key, MDB_NOOVERWRITE)) + { + weechat_printf(NULL, "%sxmpp: failed to write lmdb value", + weechat_prefix("error")); + return -1; + }; + + if (mdb_txn_commit(transaction)) { + weechat_printf(NULL, "%sxmpp: failed to write lmdb transaction", + weechat_prefix("error")); + return -1; + }; + */ + return -1; + } + + return 0; +} + +int pks_store_pre_key(uint32_t pre_key_id, uint8_t *record, size_t record_len, void *user_data) +{ + (void) pre_key_id; + (void) record; + (void) record_len; (void) user_data; + return -1; + struct t_omemo *omemo = (struct t_omemo *)user_data; + MDB_txn *transaction; + MDB_val k_pre_key = mdb_val_str("pre_key"); + MDB_val v_pre_key; + + if (mdb_txn_begin(omemo->db->env, NULL, MDB_RDONLY, &transaction)) { + weechat_printf(NULL, "%sxmpp: failed to open lmdb transaction", + weechat_prefix("error")); + } + + if (mdb_get(transaction, omemo->db->dbi_omemo, + &k_pre_key, &v_pre_key)) + { + *record = signal_buffer_create(v_pre_key.mv_data, v_pre_key.mv_size); + + if (mdb_txn_commit(transaction)) { + weechat_printf(NULL, "%sxmpp: failed to close lmdb transaction", + weechat_prefix("error")); + return -1; + }; + } + else + { + signal_protocol_key_helper_pre_key_list_node *pre_keys_list; + session_pre_key *pre_key = NULL; + + mdb_txn_abort(transaction); + + /* + signal_protocol_key_helper_generate_pre_keys( + &pre_keys_list, 0, 100, omemo->context); + pre_key = signal_protocol_key_helper_key_list_element(pre_keys_list); + signal_protocol_key_helper_key_list_next(pre_keys_list); + + uint32_t id = session_pre_key_get_id(pre_key); + session_pre_key_serialize(&record, pre_key); + + signal_protocol_key_helper_key_list_free(pre_keys_list); + + if (mdb_txn_begin(omemo->db->env, NULL, 0, &transaction)) { + weechat_printf(NULL, "%sxmpp: failed to open lmdb transaction", + weechat_prefix("error")); + return -1; + } + + v_pre_key.mv_data = signal_buffer_data(*record); + v_pre_key.mv_size = signal_buffer_len(*record); + + if (mdb_put(transaction, omemo->db->dbi_omemo, + &k_pre_key, &v_pre_key, MDB_NOOVERWRITE)) + { + weechat_printf(NULL, "%sxmpp: failed to write lmdb value", + weechat_prefix("error")); + return -1; + }; + + if (mdb_txn_commit(transaction)) { + weechat_printf(NULL, "%sxmpp: failed to write lmdb transaction", + weechat_prefix("error")); + return -1; + }; + */ + return -1; + } + + return 0; } -void unlock_function(void *user_data) +int pks_contains_pre_key(uint32_t pre_key_id, void *user_data) { + (void) pre_key_id; (void) user_data; + return -1; } -void omemo__log_emit_weechat(int level, const char *message, size_t len, void *user_data) +int pks_remove_pre_key(uint32_t pre_key_id, void *user_data) { - struct t_gui_buffer *buffer = (struct t_gui_buffer*)user_data; + (void) pre_key_id; + (void) user_data; + return -1; +} - static const char *log_level_name[5] = {"error", "warn", "notice", "info", "debug"}; +void pks_destroy_func(void *user_data) +{ + (void) user_data; +} - const char *tags = level < SG_LOG_DEBUG ? "no_log" : NULL; +int spks_load_signed_pre_key(signal_buffer **record, uint32_t signed_pre_key_id, void *user_data) +{ + (void) record; + (void) signed_pre_key_id; + (void) user_data; + return -1; + //session_signed_pre_key *signed_pre_key; + //int start_id = 0; + //time_t timestamp = time(NULL); + //signal_protocol_key_helper_generate_signed_pre_key(&signed_pre_key, new_omemo->identity, 5, timestamp, new_omemo->context); +} - weechat_printf_date_tags( - buffer, 0, tags, - _("%somemo (%s): %.*s"), - weechat_prefix("network"), - log_level_name[level], len, message); +int spks_store_signed_pre_key(uint32_t signed_pre_key_id, uint8_t *record, size_t record_len, void *user_data) +{ + (void) signed_pre_key_id; + (void) record; + (void) record_len; + (void) user_data; + return -1; } -int iks_get_identity_key_pair(signal_buffer **public_data, signal_buffer **private_data, void *user_data) +int spks_contains_signed_pre_key(uint32_t signed_pre_key_id, void *user_data) { - (void) public_data; - (void) private_data; + (void) signed_pre_key_id; (void) user_data; - // Get the local client's identity key pair + return -1; } -int iks_get_local_registration_id(void *user_data, uint32_t *registration_id) +int spks_remove_signed_pre_key(uint32_t signed_pre_key_id, void *user_data) { + (void) signed_pre_key_id; (void) user_data; - (void) registration_id; - // Return the local client's registration ID + return -1; } -int iks_save_identity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data) +void spks_destroy_func(void *user_data) { + (void) user_data; +} + +int ss_load_session_func(signal_buffer **record, signal_buffer **user_record, const signal_protocol_address *address, void *user_data) +{ + (void) record; + (void) user_record; (void) address; - (void) key_data; - (void) key_len; (void) user_data; - // Save a remote client's identity key + return -1; } -int iks_is_trusted_identity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data) +int ss_get_sub_device_sessions_func(signal_int_list **sessions, const char *name, size_t name_len, void *user_data) +{ + (void) sessions; + (void) name; + (void) name_len; + (void) user_data; + return -1; +} + +int ss_store_session_func(const signal_protocol_address *address, uint8_t *record, size_t record_len, uint8_t *user_record, size_t user_record_len, void *user_data) { (void) address; - (void) key_data; - (void) key_len; + (void) record; + (void) record_len; + (void) user_record; + (void) user_record_len; (void) user_data; - // Verify a remote client's identity key + return -1; } -void iks_destroy_func(void *user_data) +int ss_contains_session_func(const signal_protocol_address *address, void *user_data) { + (void) address; (void) user_data; - // Function called to perform cleanup when the data store context is being destroyed + return -1; } +int ss_delete_session_func(const signal_protocol_address *address, void *user_data) +{ + (void) address; + (void) user_data; + return -1; +} + +int ss_delete_all_sessions_func(const char *name, size_t name_len, void *user_data) +{ + (void) name; + (void) name_len; + (void) user_data; + return -1; +} + +void ss_destroy_func(void *user_data) +{ + (void) user_data; +} + +int sks_store_sender_key(const signal_protocol_sender_key_name *sender_key_name, uint8_t *record, size_t record_len, uint8_t *user_record, size_t user_record_len, void *user_data) +{ + (void) sender_key_name; + (void) record; + (void) record_len; + (void) user_record; + (void) user_record_len; + (void) user_data; + return -1; +} + +int sks_load_sender_key(signal_buffer **record, signal_buffer **user_record, const signal_protocol_sender_key_name *sender_key_name, void *user_data) +{ + (void) record; + (void) user_record; + (void) sender_key_name; + (void) user_data; + return -1; +} + +void sks_destroy_func(void *user_data) +{ + (void) user_data; +} + +void omemo__log_emit_weechat(int level, const char *message, size_t len, void *user_data) +{ + struct t_gui_buffer *buffer = (struct t_gui_buffer*)user_data; + + static const char *log_level_name[5] = {"error", "warn", "notice", "info", "debug"}; + + const char *tags = level < SG_LOG_DEBUG ? "no_log" : NULL; + + weechat_printf_date_tags( + buffer, 0, tags, + _("%somemo (%s): %.*s"), + weechat_prefix("network"), + log_level_name[level], len, message); +} void omemo__init(struct t_gui_buffer *buffer, struct t_omemo **omemo, const char *account_name) @@ -465,15 +957,17 @@ void omemo__init(struct t_gui_buffer *buffer, struct t_omemo **omemo, new_omemo = calloc(1, sizeof(**omemo)); + new_omemo->db = malloc(sizeof(struct t_omemo_db)); + signal_context_create(&new_omemo->context, buffer); signal_context_set_log_function(new_omemo->context, &omemo__log_emit_weechat); - mdb_env_create(&new_omemo->db.env); - mdb_env_set_maxdbs(new_omemo->db.env, 50); - mdb_env_set_mapsize(new_omemo->db.env, (size_t)1048576 * 100000); // 1MB * 100000 + mdb_env_create(&new_omemo->db->env); + mdb_env_set_maxdbs(new_omemo->db->env, 50); + mdb_env_set_mapsize(new_omemo->db->env, (size_t)1048576 * 100000); // 1MB * 100000 char *path = weechat_string_eval_expression("${weechat_data_dir}/xmpp.omemo.db", NULL, NULL, NULL); - if (mdb_env_open(new_omemo->db.env, path, MDB_NOSUBDIR, 0664) != 0) + if (mdb_env_open(new_omemo->db->env, path, MDB_NOSUBDIR, 0664) != 0) { return; } @@ -481,19 +975,20 @@ void omemo__init(struct t_gui_buffer *buffer, struct t_omemo **omemo, MDB_txn *parentTransaction = NULL; MDB_txn *transaction; - if (mdb_txn_begin(new_omemo->db.env, parentTransaction, 0 ? MDB_RDONLY : 0, &transaction)) { - //Error + if (mdb_txn_begin(new_omemo->db->env, parentTransaction, 0 ? MDB_RDONLY : 0, &transaction)) { + weechat_printf(NULL, "%sxmpp: failed to open lmdb transaction", + weechat_prefix("error")); } - if (0) { - mdb_txn_abort(transaction); - } else { - mdb_txn_commit(transaction); + size_t db_name_len = strlen("omemo_") + strlen(account_name); + char *db_name = malloc(sizeof(char) * (db_name_len + 1)); + snprintf(db_name, db_name_len+1, "identity_key_%s", account_name); + if (mdb_dbi_open(transaction, db_name, MDB_DUPSORT | MDB_CREATE, &new_omemo->db->dbi_omemo)) { + weechat_printf(NULL, "%sxmpp: failed to open lmdb database", + weechat_prefix("error")); } - if (mdb_dbi_open(transaction, "databasename", MDB_DUPSORT | MDB_CREATE, new_omemo->db.dbi)) { - //Error - } + mdb_txn_abort(transaction); struct signal_crypto_provider crypto_provider = { .random_func = &cp_random_generator, @@ -507,28 +1002,12 @@ void omemo__init(struct t_gui_buffer *buffer, struct t_omemo **omemo, .sha512_digest_cleanup_func = &cp_sha512_digest_cleanup, .encrypt_func = &cp_encrypt, .decrypt_func = &cp_decrypt, - .user_data = buffer, + .user_data = new_omemo, }; signal_context_set_crypto_provider(new_omemo->context, &crypto_provider); signal_context_set_locking_functions(new_omemo->context, &lock_function, &unlock_function); - signal_protocol_key_helper_pre_key_list_node *pre_keys_head; - session_signed_pre_key *signed_pre_key; - int start_id = 0; - time_t timestamp = time(NULL); - - if (new_omemo->identity) - 0; - else - signal_protocol_key_helper_generate_identity_key_pair(&new_omemo->identity, new_omemo->context); - signal_protocol_key_helper_generate_registration_id(&new_omemo->device_id, 0, new_omemo->context); - signal_protocol_key_helper_generate_pre_keys(&pre_keys_head, start_id, 100, new_omemo->context); - signal_protocol_key_helper_generate_signed_pre_key(&signed_pre_key, new_omemo->identity, 5, timestamp, new_omemo->context); - - /* Store pre keys in the pre key store. */ - /* Store signed pre key in the signed pre key store. */ - signal_protocol_store_context_create(&new_omemo->store_context, new_omemo->context); struct signal_protocol_identity_key_store identity_key_store = { @@ -537,10 +1016,59 @@ void omemo__init(struct t_gui_buffer *buffer, struct t_omemo **omemo, .save_identity = &iks_save_identity, .is_trusted_identity = &iks_is_trusted_identity, .destroy_func = &iks_destroy_func, - .user_data = account_name, + .user_data = new_omemo, + }; + + signal_protocol_store_context_set_identity_key_store( + new_omemo->store_context, &identity_key_store); + + struct signal_protocol_pre_key_store pre_key_store = { + .load_pre_key = &pks_load_pre_key, + .store_pre_key = &pks_store_pre_key, + .contains_pre_key = &pks_contains_pre_key, + .remove_pre_key = &pks_remove_pre_key, + .destroy_func = &pks_destroy_func, + .user_data = new_omemo, + }; + + signal_protocol_store_context_set_pre_key_store( + new_omemo->store_context, &pre_key_store); + + struct signal_protocol_signed_pre_key_store signed_pre_key_store = { + .load_signed_pre_key = &spks_load_signed_pre_key, + .store_signed_pre_key = &spks_store_signed_pre_key, + .contains_signed_pre_key = &spks_contains_signed_pre_key, + .remove_signed_pre_key = &spks_remove_signed_pre_key, + .destroy_func = &spks_destroy_func, + .user_data = new_omemo, + }; + + signal_protocol_store_context_set_signed_pre_key_store( + new_omemo->store_context, &signed_pre_key_store); + + struct signal_protocol_session_store session_store = { + .load_session_func = &ss_load_session_func, + .get_sub_device_sessions_func = &ss_get_sub_device_sessions_func, + .store_session_func = &ss_store_session_func, + .contains_session_func = &ss_contains_session_func, + .delete_session_func = &ss_delete_session_func, + .delete_all_sessions_func = &ss_delete_all_sessions_func, + .destroy_func = &ss_destroy_func, + .user_data = new_omemo, + }; + + signal_protocol_store_context_set_session_store( + new_omemo->store_context, &session_store); + + struct signal_protocol_sender_key_store sender_key_store = { + .store_sender_key = &sks_store_sender_key, + .load_sender_key = &sks_load_sender_key, + .destroy_func = &sks_destroy_func, + .user_data = new_omemo, }; - signal_protocol_store_context_set_identity_key_store(new_omemo->store_context, &identity_key_store); + signal_protocol_store_context_set_sender_key_store( + new_omemo->store_context, &sender_key_store); *omemo = new_omemo; } diff --git a/omemo.h b/omemo.h index 5a28254..03c29b2 100644 --- a/omemo.h +++ b/omemo.h @@ -12,10 +12,7 @@ struct t_omemo struct signal_context *context; struct signal_protocol_store_context *store_context; - struct { - struct MDB_env *env; - struct MDB_dbi *dbi; - } db; + struct t_omemo_db *db; struct ratchet_identity_key_pair *identity; diff --git a/pgp.c b/pgp.c index 9d4aed0..427bf85 100644 --- a/pgp.c +++ b/pgp.c @@ -60,7 +60,7 @@ void pgp__free(struct t_pgp *pgp) } } -char *pgp__encrypt(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *target, const char *message) +char *pgp__encrypt(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *source, const char *target, const char *message) { rnp_op_encrypt_t encrypt = NULL; rnp_key_handle_t key = NULL; @@ -115,6 +115,21 @@ char *pgp__encrypt(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *t rnp_key_handle_destroy(key); key = NULL; + /* locate carbon-copy key and add it to the operation context. */ + if ((ret = rnp_locate_key(pgp->context, "keyid", source, &key)) != RNP_SUCCESS) { + const char *reason = rnp_result_to_string(ret); + weechat_printf(buffer, "%spgp: failed to locate recipient key: %s\n", weechat_prefix("error"), reason); + goto encrypt_finish; + } + + if ((ret = rnp_op_encrypt_add_recipient(encrypt, key)) != RNP_SUCCESS) { + const char *reason = rnp_result_to_string(ret); + weechat_printf(buffer, "%spgp: failed to add recipient: %s\n", weechat_prefix("error"), reason); + goto encrypt_finish; + } + rnp_key_handle_destroy(key); + key = NULL; + /* execute encryption operation */ if ((ret = rnp_op_encrypt_execute(encrypt)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); diff --git a/pgp.h b/pgp.h index ab73475..0e12e6a 100644 --- a/pgp.h +++ b/pgp.h @@ -19,7 +19,7 @@ void pgp__free(struct t_pgp *pgp); char *pgp__decrypt(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *ciphertext); -char *pgp__encrypt(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *target, const char *message); +char *pgp__encrypt(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *source, const char *target, const char *message); char *pgp__verify(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *certificate); diff --git a/user.c b/user.c index 5d9ed62..5190f69 100644 --- a/user.c +++ b/user.c @@ -184,7 +184,7 @@ struct t_user *user__new(struct t_account *account, new_user->profile.avatar_hash = NULL; new_user->profile.status_text = NULL; new_user->profile.status = NULL; - new_user->profile.real_name = NULL; + new_user->profile.idle = NULL; new_user->profile.display_name = display_name ? strdup(display_name) : strdup(""); new_user->profile.affiliation = NULL; @@ -232,8 +232,8 @@ void user__free(struct t_account *account, free(user->profile.status_text); if (user->profile.status) free(user->profile.status); - if (user->profile.real_name) - free(user->profile.real_name); + if (user->profile.idle) + free(user->profile.idle); if (user->profile.display_name) free(user->profile.display_name); if (user->profile.affiliation) diff --git a/user.h b/user.h index 74c3654..9c153c5 100644 --- a/user.h +++ b/user.h @@ -10,7 +10,7 @@ struct t_user_profile char *avatar_hash; char *status_text; char *status; - char *real_name; + char *idle; char *display_name; char *email; char *role;