omemo progress++

v2
Tony Olagbaiye 3 years ago
parent d3ffc19378
commit 5eca4ac37c
No known key found for this signature in database
GPG Key ID: 9E2FF3BDEBDFC910

@ -40,7 +40,7 @@ use_guix()
libtool # Deps with libtool libtool # Deps with libtool
make # Makefile and deps with makefiles make # Makefile and deps with makefiles
cmake # Deps with cmake cmake # Deps with cmake
gcc-toolchain # Compilation gcc-toolchain@11 # Compilation
pkg-config # Deps configuration and configuration of deps deps pkg-config # Deps configuration and configuration of deps deps
patchelf # Fix linkage (guix) patchelf # Fix linkage (guix)
bear # Generate compile_commands.json for language servers bear # Generate compile_commands.json for language servers

@ -28,6 +28,9 @@
A weechat plugin in C to extend the chat client to A weechat plugin in C to extend the chat client to
support XMPP and a currently minimal but ideally maximal support XMPP and a currently minimal but ideally maximal
set of XEPs. 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 I'm gonna rewrite this in C++ at some point when I have a feel
for the full behaviour of an average client. for the full behaviour of an average client.
@ -132,6 +135,11 @@
* [X] [#A] Recv typing notifications * [X] [#A] Recv typing notifications
* [X] [#C] Read receipts * [X] [#C] Read receipts
* [X] Chat Markers (XEP-0333) * [X] Chat Markers (XEP-0333)
* [X] Composing
* [X] Paused
* [?] Active
* [ ] Inactive
* [ ] Gone
* [X] Message Delivery (XEP-0184) * [X] Message Delivery (XEP-0184)
* [X] Message Carbons * [X] Message Carbons
* [ ] Service Disco * [ ] Service Disco

@ -165,6 +165,95 @@ void account__free_device_all(struct t_account *account)
account__free_device(account, account->devices); 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, void account__log_emit_weechat(void *const userdata, const xmpp_log_level_t level,
const char *const area, const char *const msg) 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->devices = NULL;
new_account->last_device = NULL; new_account->last_device = NULL;
new_account->mam_queries = NULL;
new_account->last_mam_query = NULL;
new_account->users = NULL; new_account->users = NULL;
new_account->last_user = NULL; new_account->last_user = NULL;
new_account->channels = NULL; new_account->channels = NULL;
@ -364,6 +455,8 @@ void account__free_data(struct t_account *account)
xmpp_redirect_free_all(account); xmpp_redirect_free_all(account);
xmpp_notify_free_all(account); xmpp_notify_free_all(account);
*/ */
account__free_device_all(account);
account__mam_query_free_all(account);
channel__free_all(account); channel__free_all(account);
user__free_all(account); user__free_all(account);

@ -73,6 +73,19 @@ struct t_account_device
struct t_account_device *next_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 struct t_account
{ {
char *name; char *name;
@ -99,6 +112,8 @@ struct t_account
struct t_account_device *devices; struct t_account_device *devices;
struct t_account_device *last_device; 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 *users;
struct t_user *last_user; struct t_user *last_user;
struct t_channel *channels; 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__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(struct t_account *account, struct t_account_device *device);
void account__free_device_all(struct t_account *account); 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); struct t_account *account__alloc(const char *name);
void account__free_data(struct t_account *account); void account__free_data(struct t_account *account);
void account__free(struct t_account *account); void account__free(struct t_account *account);

@ -314,7 +314,7 @@ struct t_channel *channel__new(struct t_account *account,
struct tm *ago = gmtime(&start); struct tm *ago = gmtime(&start);
ago->tm_mday -= 7; ago->tm_mday -= 7;
start = mktime(ago); start = mktime(ago);
channel__fetch_mam(account, new_channel, &start, NULL); channel__fetch_mam(account, new_channel, NULL, &start, NULL, NULL);
} }
return new_channel; return new_channel;
@ -886,7 +886,7 @@ struct t_channel_member *channel__add_member(struct t_account *account,
client ? ")" : "", client ? ")" : "",
user->profile.status ? "is " : "", user->profile.status ? "is " : "",
weechat_color("irc.color.message_join"), 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"), weechat_color("reset"),
channel->id, channel->id,
user->profile.status_text ? " [" : "", 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 ? user->profile.pgp_id : "",
user->profile.pgp_id ? weechat_color("reset") : ""); user->profile.pgp_id ? weechat_color("reset") : "");
else 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"), weechat_prefix("join"),
jid_resource ? user__as_prefix_raw(account, jid_bare) : "You", jid_resource ? user__as_prefix_raw(account, jid_bare) : "You",
jid_resource ? jid_resource : user__as_prefix_raw(account, jid_bare), jid_resource ? jid_resource : user__as_prefix_raw(account, jid_bare),
user->profile.status ? "is " : "", user->profile.status ? "is " : "",
weechat_color("irc.color.message_join"), 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"), 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 : "", 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_stanza_set_id(message, id);
xmpp_free(account->context, id); xmpp_free(account->context, id);
xmpp_message_set_body(message, body);
char *url = strstr(body, "http"); char *url = strstr(body, "http");
if (channel->pgp_id) 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_set_ns(message__x, "jabber:x:encrypted");
xmpp_stanza_t *message__x__text = xmpp_stanza_new(account->context); 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) if (ciphertext)
xmpp_stanza_set_text(message__x__text, ciphertext); xmpp_stanza_set_text(message__x__text, ciphertext);
free(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_add_child(message, message__x);
xmpp_stanza_release(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); xmpp_message_set_body(message, PGP_ADVICE);
if (ciphertext && channel->transport != CHANNEL_TRANSPORT_PGP) if (ciphertext && channel->transport != CHANNEL_TRANSPORT_PGP)
@ -1027,13 +1034,18 @@ void channel__send_message(struct t_account *account, struct t_channel *channel,
channel__transport_name(channel->transport)); channel__transport_name(channel->transport));
} }
} }
else if (channel->transport != CHANNEL_TRANSPORT_PLAINTEXT) else
{
xmpp_message_set_body(message, body);
if (channel->transport != CHANNEL_TRANSPORT_PLAINTEXT)
{ {
channel->transport = CHANNEL_TRANSPORT_PLAINTEXT; channel->transport = CHANNEL_TRANSPORT_PLAINTEXT;
weechat_printf_date_tags(channel->buffer, 0, NULL, "%s%sTransport: %s", weechat_printf_date_tags(channel->buffer, 0, NULL, "%s%sTransport: %s",
weechat_prefix("network"), weechat_color("gray"), weechat_prefix("network"), weechat_color("gray"),
channel__transport_name(channel->transport)); channel__transport_name(channel->transport));
} }
}
if (url) 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_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_send(account->connection, message);
xmpp_stanza_release(message); xmpp_stanza_release(message);
if (channel->type != CHANNEL_TYPE_MUC) 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, 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_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_t *query = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(query, "query"); 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_add_child(query, x);
xmpp_stanza_release(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_add_child(iq, query);
xmpp_stanza_release(query); xmpp_stanza_release(query);

@ -191,6 +191,6 @@ void channel__send_paused(struct t_account *account, struct t_channel *channel,
struct t_user *user); struct t_user *user);
void channel__fetch_mam(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);
#endif /*WEECHAT_XMPP_CHANNEL_H*/ #endif /*WEECHAT_XMPP_CHANNEL_H*/

@ -752,7 +752,7 @@ int command__mam(const void *pointer, void *data,
else else
ago->tm_mday -= MAM_DEFAULT_DAYS; ago->tm_mday -= MAM_DEFAULT_DAYS;
start = mktime(ago); 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; return WEECHAT_RC_OK;
} }

@ -37,7 +37,24 @@ void config__account_change_cb(const void *pointer, void *data,
{ {
(void) pointer; (void) pointer;
(void) data; (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, void config__account_default_change_cb(const void *pointer, void *data,

@ -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_account *account = (struct t_account *)userdata;
struct t_user *user; struct t_user *user;
struct t_channel *channel; 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 *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; char *clientid = NULL, *status;
from = xmpp_stanza_get_from(stanza); 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); type = xmpp_stanza_get_type(stanza);
show = xmpp_stanza_get_child_by_name(stanza, "show"); show = xmpp_stanza_get_child_by_name(stanza, "show");
show__text = show ? xmpp_stanza_get_text(show) : NULL; 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( iq__x_signed = xmpp_stanza_get_child_by_name_and_ns(
stanza, "x", "jabber:x:signed"); stanza, "x", "jabber:x:signed");
if (iq__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); ? from_res : from);
user->profile.status_text = status ? strdup(status) : NULL; user->profile.status_text = status ? strdup(status) : NULL;
user->profile.status = show ? strdup(show__text) : 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->is_away = show ? weechat_strcasecmp(show__text, "away") == 0 : 0;
user->profile.role = role ? strdup(role) : NULL; user->profile.role = role ? strdup(role) : NULL;
user->profile.affiliation = affiliation && strcmp(affiliation, "none") != 0 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); ? from_res : from);
user->profile.status_text = status ? strdup(status) : NULL; user->profile.status_text = status ? strdup(status) : NULL;
user->profile.status = show ? strdup(show__text) : 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.role = role ? strdup(role) : NULL;
user->profile.affiliation = affiliation && strcmp(affiliation, "none") != 0 user->profile.affiliation = affiliation && strcmp(affiliation, "none") != 0
? strdup(affiliation) : NULL; ? 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) int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{ {
(void) conn;
struct t_account *account = (struct t_account *)userdata; 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 *pubsub, *items, *item, *list, *device, **children;
xmpp_stanza_t *storage, *conference, *nick; xmpp_stanza_t *storage, *conference, *nick;
static struct utsname osinfo; static struct utsname osinfo;
const char *id = xmpp_stanza_get_id(stanza);
query = xmpp_stanza_get_child_by_name_and_ns( query = xmpp_stanza_get_child_by_name_and_ns(
stanza, "query", "http://jabber.org/protocol/disco#info"); stanza, "query", "http://jabber.org/protocol/disco#info");
const char *type = xmpp_stanza_get_attribute(stanza, "type"); 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; return 1;
} }

@ -9,32 +9,36 @@
#include <gcrypt.h> #include <gcrypt.h>
#include <signal_protocol.h> #include <signal_protocol.h>
#include <key_helper.h> #include <key_helper.h>
#include <curve.h>
#include <lmdb.h> #include <lmdb.h>
#include <strophe.h> #include <strophe.h>
#include <weechat/weechat-plugin.h> #include <weechat/weechat-plugin.h>
struct t_omemo_db {
MDB_env *env;
MDB_dbi dbi_omemo;
};
#include "plugin.h" #include "plugin.h"
#include "account.h" #include "account.h"
#include "omemo.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) { #define mdb_val_intptr(i) { \
if (!(instance != NULL)) .mv_data = i, .mv_size = sizeof(*i), \
return NULL;
signal_type_ref(instance);
return instance;
} }
signal_type_base* signal_type_unref_vapi(void* instance) { #define mdb_val_sizeof(t) { \
if (!(instance != NULL)) .mv_data = NULL, .mv_size = sizeof(t), \
return NULL;
signal_type_unref(instance);
return NULL;
} }
const char *OMEMO_ADVICE = "[OMEMO encrypted message (XEP-0384)]";
void signal_protocol_address_free(signal_protocol_address* ptr) { void signal_protocol_address_free(signal_protocol_address* ptr) {
if (!(ptr != NULL)) if (!ptr)
return; return;
if (ptr->name) { if (ptr->name) {
free((void*)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) { void signal_protocol_address_set_name(signal_protocol_address* self, const char* name) {
if (!(self != NULL)) if (!self)
return; return;
if (!(name != NULL)) if (!name)
return; return;
char* n = malloc(strlen(name)+1); char* n = malloc(strlen(name)+1);
memcpy(n, name, strlen(name)); 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) { char* signal_protocol_address_get_name(signal_protocol_address* self) {
if (!(self != NULL)) if (!self)
return NULL; return NULL;
if (!(self->name != NULL)) if (!self->name)
return 0; return 0;
char* res = malloc(sizeof(char) * (self->name_len + 1)); char* res = malloc(sizeof(char) * (self->name_len + 1));
memcpy(res, self->name, self->name_len); 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) { int32_t signal_protocol_address_get_device_id(signal_protocol_address* self) {
if (!(self != NULL)) if (!self)
return -1; return -1;
return self->device_id; return self->device_id;
} }
void signal_protocol_address_set_device_id(signal_protocol_address* self, int32_t device_id) { void signal_protocol_address_set_device_id(signal_protocol_address* self, int32_t device_id) {
if (!(self != NULL)) if (!self)
return; return;
self->device_id = device_id; self->device_id = device_id;
} }
signal_protocol_address* signal_protocol_address_new(const char* name, int32_t device_id) { signal_protocol_address* signal_protocol_address_new(const char* name, int32_t device_id) {
if (!(name != NULL)) if (!name)
return NULL; return NULL;
signal_protocol_address* address = malloc(sizeof(signal_protocol_address)); signal_protocol_address* address = malloc(sizeof(signal_protocol_address));
address->device_id = -1; address->device_id = -1;
@ -91,6 +95,43 @@ signal_protocol_address* signal_protocol_address_new(const char* name, int32_t d
return address; 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) { int cp_randomize(uint8_t *data, size_t len) {
gcry_randomize(data, len, GCRY_STRONG_RANDOM); gcry_randomize(data, len, GCRY_STRONG_RANDOM);
return SG_SUCCESS; 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 cp_encrypt(signal_buffer **output,
int cipher, int cipher,
const uint8_t *key, size_t key_len, const uint8_t *key, size_t key_len,
@ -391,70 +405,548 @@ no_error:
return SG_SUCCESS; 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; (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"));
} }
void unlock_function(void *user_data) 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_contains_pre_key(uint32_t pre_key_id, void *user_data)
{
(void) pre_key_id;
(void) user_data; (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( int spks_store_signed_pre_key(uint32_t signed_pre_key_id, uint8_t *record, size_t record_len, void *user_data)
buffer, 0, tags, {
_("%somemo (%s): %.*s"), (void) signed_pre_key_id;
weechat_prefix("network"), (void) record;
log_level_name[level], len, message); (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) signed_pre_key_id;
(void) private_data;
(void) user_data; (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) user_data;
(void) registration_id; return -1;
// Return the local client's registration ID
} }
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) address;
(void) key_data;
(void) key_len;
(void) user_data; (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) address;
(void) key_data; (void) record;
(void) key_len; (void) record_len;
(void) user_record;
(void) user_record_len;
(void) user_data; (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; (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, void omemo__init(struct t_gui_buffer *buffer, struct t_omemo **omemo,
const char *account_name) 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 = calloc(1, sizeof(**omemo));
new_omemo->db = malloc(sizeof(struct t_omemo_db));
signal_context_create(&new_omemo->context, buffer); signal_context_create(&new_omemo->context, buffer);
signal_context_set_log_function(new_omemo->context, &omemo__log_emit_weechat); signal_context_set_log_function(new_omemo->context, &omemo__log_emit_weechat);
mdb_env_create(&new_omemo->db.env); mdb_env_create(&new_omemo->db->env);
mdb_env_set_maxdbs(new_omemo->db.env, 50); 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_set_mapsize(new_omemo->db->env, (size_t)1048576 * 100000); // 1MB * 100000
char *path = weechat_string_eval_expression("${weechat_data_dir}/xmpp.omemo.db", char *path = weechat_string_eval_expression("${weechat_data_dir}/xmpp.omemo.db",
NULL, NULL, NULL); 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; return;
} }
@ -481,19 +975,20 @@ void omemo__init(struct t_gui_buffer *buffer, struct t_omemo **omemo,
MDB_txn *parentTransaction = NULL; MDB_txn *parentTransaction = NULL;
MDB_txn *transaction; MDB_txn *transaction;
if (mdb_txn_begin(new_omemo->db.env, parentTransaction, 0 ? MDB_RDONLY : 0, &transaction)) { if (mdb_txn_begin(new_omemo->db->env, parentTransaction, 0 ? MDB_RDONLY : 0, &transaction)) {
//Error weechat_printf(NULL, "%sxmpp: failed to open lmdb transaction",
weechat_prefix("error"));
} }
if (0) { size_t db_name_len = strlen("omemo_") + strlen(account_name);
mdb_txn_abort(transaction); char *db_name = malloc(sizeof(char) * (db_name_len + 1));
} else { snprintf(db_name, db_name_len+1, "identity_key_%s", account_name);
mdb_txn_commit(transaction); 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)) { mdb_txn_abort(transaction);
//Error
}
struct signal_crypto_provider crypto_provider = { struct signal_crypto_provider crypto_provider = {
.random_func = &cp_random_generator, .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, .sha512_digest_cleanup_func = &cp_sha512_digest_cleanup,
.encrypt_func = &cp_encrypt, .encrypt_func = &cp_encrypt,
.decrypt_func = &cp_decrypt, .decrypt_func = &cp_decrypt,
.user_data = buffer, .user_data = new_omemo,
}; };
signal_context_set_crypto_provider(new_omemo->context, &crypto_provider); signal_context_set_crypto_provider(new_omemo->context, &crypto_provider);
signal_context_set_locking_functions(new_omemo->context, &lock_function, &unlock_function); 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); signal_protocol_store_context_create(&new_omemo->store_context, new_omemo->context);
struct signal_protocol_identity_key_store identity_key_store = { 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, .save_identity = &iks_save_identity,
.is_trusted_identity = &iks_is_trusted_identity, .is_trusted_identity = &iks_is_trusted_identity,
.destroy_func = &iks_destroy_func, .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; *omemo = new_omemo;
} }

@ -12,10 +12,7 @@ struct t_omemo
struct signal_context *context; struct signal_context *context;
struct signal_protocol_store_context *store_context; struct signal_protocol_store_context *store_context;
struct { struct t_omemo_db *db;
struct MDB_env *env;
struct MDB_dbi *dbi;
} db;
struct ratchet_identity_key_pair *identity; struct ratchet_identity_key_pair *identity;

17
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_op_encrypt_t encrypt = NULL;
rnp_key_handle_t key = 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); rnp_key_handle_destroy(key);
key = NULL; 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 */ /* execute encryption operation */
if ((ret = rnp_op_encrypt_execute(encrypt)) != RNP_SUCCESS) { if ((ret = rnp_op_encrypt_execute(encrypt)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); const char *reason = rnp_result_to_string(ret);

@ -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__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); char *pgp__verify(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *certificate);

@ -184,7 +184,7 @@ struct t_user *user__new(struct t_account *account,
new_user->profile.avatar_hash = NULL; new_user->profile.avatar_hash = NULL;
new_user->profile.status_text = NULL; new_user->profile.status_text = NULL;
new_user->profile.status = NULL; new_user->profile.status = NULL;
new_user->profile.real_name = NULL; new_user->profile.idle = NULL;
new_user->profile.display_name = display_name ? new_user->profile.display_name = display_name ?
strdup(display_name) : strdup(""); strdup(display_name) : strdup("");
new_user->profile.affiliation = NULL; new_user->profile.affiliation = NULL;
@ -232,8 +232,8 @@ void user__free(struct t_account *account,
free(user->profile.status_text); free(user->profile.status_text);
if (user->profile.status) if (user->profile.status)
free(user->profile.status); free(user->profile.status);
if (user->profile.real_name) if (user->profile.idle)
free(user->profile.real_name); free(user->profile.idle);
if (user->profile.display_name) if (user->profile.display_name)
free(user->profile.display_name); free(user->profile.display_name);
if (user->profile.affiliation) if (user->profile.affiliation)

@ -10,7 +10,7 @@ struct t_user_profile
char *avatar_hash; char *avatar_hash;
char *status_text; char *status_text;
char *status; char *status;
char *real_name; char *idle;
char *display_name; char *display_name;
char *email; char *email;
char *role; char *role;

Loading…
Cancel
Save