Commit 631f993c authored by Richard Bayerle's avatar Richard Bayerle
Browse files

Add functions for retrieving fingerprints

parent dfb75111
......@@ -13,7 +13,11 @@
#define MODULE_NAME "lurch-api"
void lurch_api_id_list_handler(PurpleAccount * acc_p, void (*cb)(int32_t err, GList * id_list, void * user_data_p), void * user_data_p) {
/**
* Returns a GList of int32_t * containing the devices of the calling account.
* If the current device is contained in it (which it should be!), it will be first in the list.
*/
static int32_t lurch_api_id_list_get_own(PurpleAccount * acc_p, GList ** list_pp) {
int32_t ret_val = 0;
char * uname = (void *) 0;
char * db_fn_omemo = (void *) 0;
......@@ -44,6 +48,11 @@ void lurch_api_id_list_handler(PurpleAccount * acc_p, void (*cb)(int32_t err, GL
goto cleanup;
}
if (!omemo_devicelist_contains_id(dl_p, own_id)) {
purple_debug_warning(MODULE_NAME, "This device's ID is not contained in your devicelist?");
goto cleanup;
}
ret_val = omemo_devicelist_remove(dl_p, own_id);
if (ret_val) {
purple_debug_error(MODULE_NAME, "Failed to remove the ID from the devicelist.");
......@@ -52,7 +61,7 @@ void lurch_api_id_list_handler(PurpleAccount * acc_p, void (*cb)(int32_t err, GL
id_list = omemo_devicelist_get_id_list(dl_p);
id_p = malloc(sizeof(uint32_t));
id_p = g_malloc(sizeof(uint32_t));
if (!id_p) {
ret_val = LURCH_ERR_NOMEM;
goto cleanup;
......@@ -62,12 +71,31 @@ void lurch_api_id_list_handler(PurpleAccount * acc_p, void (*cb)(int32_t err, GL
id_list = g_list_prepend(id_list, id_p);
cleanup:
cb(ret_val, id_list, user_data_p);
if (!ret_val) {
*list_pp = id_list;
}
g_free(uname);
g_free(db_fn_omemo);
omemo_devicelist_destroy(dl_p);
axc_context_destroy_all(axc_ctx_p);
return ret_val;
}
void lurch_api_id_list_handler(PurpleAccount * acc_p, void (*cb)(int32_t err, GList * id_list, void * user_data_p), void * user_data_p) {
int32_t ret_val = 0;
GList * id_list = (void *) 0;
ret_val = lurch_api_id_list_get_own(acc_p, &id_list);
if (ret_val) {
purple_debug_error(MODULE_NAME, "Failed to get the own, sorted ID list.");
goto cleanup;
}
cleanup:
cb(ret_val, id_list, user_data_p);
g_list_free_full(id_list, free);
}
......@@ -191,6 +219,155 @@ cleanup:
axc_context_destroy_all(axc_ctx_p);
}
/**
* Given a list of IDs, retrieves the public keys from the libsignal sessions and creates hash table with ID to fingerprint pairs.
* If there is an entry in the devicelist, but no session yet, the fingerprint cannot be retrieved this way and the value will be NULL.
* g_hash_table_destroy() the table when done with it.
*/
static int32_t lurch_api_fp_create_table(const char * jid, axc_context * axc_ctx_p, const GList * id_list, GHashTable ** id_fp_table_pp) {
int32_t ret_val = 0;
GHashTable * id_fp_table = (void *) 0;
const GList * curr_p = (void *) 0;
uint32_t curr_device_id = 0;
axc_buf * key_buf_p = (void *) 0;
gchar * fp = (void *) 0;
id_fp_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, g_free);
for (curr_p = id_list; curr_p; curr_p = curr_p->next) {
curr_device_id = omemo_devicelist_list_data(curr_p);
ret_val = axc_key_load_public_addr(jid, curr_device_id, axc_ctx_p, &key_buf_p);
if (ret_val < 0) {
purple_debug_error(MODULE_NAME, "Failed to load key for %s:%i", jid, curr_device_id);
goto cleanup;
} else if (ret_val == 0) {
purple_debug_warning(MODULE_NAME, "Tried to load public key for %s:%i, but no session exists", jid, curr_device_id);
(void) g_hash_table_insert(id_fp_table, curr_p->data, NULL);
continue;
}
fp = purple_base16_encode_chunked(axc_buf_get_data(key_buf_p), axc_buf_get_len(key_buf_p));
(void) g_hash_table_insert(id_fp_table, curr_p->data, lurch_util_fp_get_printable(fp));
axc_buf_free(key_buf_p);
key_buf_p = (void *) 0;
g_free(fp);
fp = (void *) 0;
ret_val = 0;
}
cleanup:
if (ret_val) {
g_hash_table_destroy(id_fp_table);
} else {
*id_fp_table_pp = id_fp_table;
}
return ret_val;
}
// returns NULL as hash table if devicelist is empty
void lurch_api_fp_list_handler(PurpleAccount * acc_p, void (*cb)(int32_t err, GHashTable * id_fp_table, void * user_data_p), void * user_data_p) {
int32_t ret_val = 0;
GList * own_id_list = (void *) 0;
char * uname = (void *) 0;
axc_context * axc_ctx_p = (void *) 0;
GHashTable * id_fp_table = (void *) 0;
axc_buf * key_buf_p = (void *) 0;
gchar * fp = (void *) 0;
ret_val = lurch_api_id_list_get_own(acc_p, &own_id_list);
if (ret_val) {
purple_debug_error(MODULE_NAME, "Failed to get the own, sorted ID list.");
goto cleanup;
}
if (g_list_length(own_id_list) == 0) {
goto cleanup;
}
uname = lurch_util_uname_strip(purple_account_get_username(acc_p));
ret_val = lurch_util_axc_get_init_ctx(uname, &axc_ctx_p);
if (ret_val) {
purple_debug_error(MODULE_NAME, "Failed to create axc ctx for %s.", uname);
goto cleanup;
}
ret_val = lurch_api_fp_create_table(uname, axc_ctx_p, own_id_list->next, &id_fp_table);
if (ret_val) {
goto cleanup;
}
ret_val = axc_key_load_public_own(axc_ctx_p, &key_buf_p);
if (ret_val) {
purple_debug_error("Failed to load public key from axc db %s.", axc_context_get_db_fn(axc_ctx_p));
goto cleanup;
}
fp = purple_base16_encode_chunked(axc_buf_get_data(key_buf_p), axc_buf_get_len(key_buf_p));
(void) g_hash_table_insert(id_fp_table, own_id_list->data, lurch_util_fp_get_printable(fp));
g_free(fp);
fp = (void *) 0;
cleanup:
cb(ret_val, id_fp_table, user_data_p);
g_list_free_full(own_id_list, g_free);
g_free(uname);
axc_context_destroy_all(axc_ctx_p);
g_hash_table_destroy(id_fp_table);
axc_buf_free(key_buf_p);
g_free(fp);
}
// returns NULL as hash table if devicelist is empty
void lurch_api_fp_other_handler(PurpleAccount * acc_p, const char * contact_bare_jid, void (*cb)(int32_t err, GHashTable * id_fp_table, void * user_data_p), void * user_data_p) {
int32_t ret_val = 0;
char * uname = (void *) 0;
char * db_fn_omemo = (void *) 0;
omemo_devicelist * dl_p = (void *) 0;
axc_context * axc_ctx_p = (void *) 0;
GHashTable * id_fp_table = (void *) 0;
GList * id_list = (void *) 0;
axc_buf * key_buf_p = (void *) 0;
uname = lurch_util_uname_strip(purple_account_get_username(acc_p));
db_fn_omemo = lurch_util_uname_get_db_fn(uname, LURCH_DB_NAME_OMEMO);
ret_val = omemo_storage_user_devicelist_retrieve(contact_bare_jid, db_fn_omemo, &dl_p);
if (ret_val) {
purple_debug_error(MODULE_NAME, "Failed to access OMEMO DB %s.", db_fn_omemo);
goto cleanup;
}
if (omemo_devicelist_is_empty(dl_p)) {
goto cleanup;
}
ret_val = lurch_util_axc_get_init_ctx(uname, &axc_ctx_p);
if (ret_val) {
purple_debug_error(MODULE_NAME, "Failed to create axc ctx for %s.", uname);
goto cleanup;
}
id_list = omemo_devicelist_get_id_list(dl_p);
ret_val = lurch_api_fp_create_table(contact_bare_jid, axc_ctx_p, id_list, &id_fp_table);
cleanup:
cb(ret_val, id_fp_table, user_data_p);
g_free(uname);
g_free(db_fn_omemo);
omemo_devicelist_destroy(dl_p);
axc_context_destroy_all(axc_ctx_p);
g_hash_table_destroy(id_fp_table);
g_list_free_full(id_list, free);
axc_buf_free(key_buf_p);
}
void lurch_api_status_im_handler(PurpleAccount * acc_p, const char * contact_bare_jid, void (*cb)(int32_t err, lurch_status_t status, void * user_data_p), void * user_data_p) {
int32_t ret_val = 0;
lurch_status_t status = LURCH_STATUS_DISABLED;
......@@ -274,7 +451,7 @@ typedef enum {
* When adding a new signal: increase this number and add the name, handler function, and handler function type
* to the respective array.
*/
#define NUM_OF_SIGNALS 6
#define NUM_OF_SIGNALS 8
const char * signal_names[NUM_OF_SIGNALS] = {
"lurch-id-list",
......@@ -282,6 +459,8 @@ const char * signal_names[NUM_OF_SIGNALS] = {
"lurch-enable-im",
"lurch-disable-im",
"lurch-fp-get",
"lurch-fp-list",
"lurch-fp-other",
"lurch-status-im"
};
......@@ -291,6 +470,8 @@ const void * signal_handlers[NUM_OF_SIGNALS] = {
lurch_api_enable_im_handler,
lurch_api_disable_im_handler,
lurch_api_fp_get_handler,
lurch_api_fp_list_handler,
lurch_api_fp_other_handler,
lurch_api_status_im_handler
};
......@@ -300,6 +481,8 @@ const lurch_api_handler_t signal_handler_types[NUM_OF_SIGNALS] = {
LURCH_API_HANDLER_ACC_JID_CB_DATA,
LURCH_API_HANDLER_ACC_JID_CB_DATA,
LURCH_API_HANDLER_ACC_CB_DATA,
LURCH_API_HANDLER_ACC_CB_DATA,
LURCH_API_HANDLER_ACC_JID_CB_DATA,
LURCH_API_HANDLER_ACC_JID_CB_DATA
};
......
......@@ -24,7 +24,8 @@ static void lurch_cmd_help(PurpleConversation * conv_p) {
" - '/lurch id list': Displays this account's device list.\n"
" - '/lurch id remove <id>': Removes the device ID <id> from this account's device list.\n"
" - '/lurch fp show': Displays this device's key fingerprint.\n"
" - '/lurch fp conv': Displays the fingerprints of all devices participating in this conversation.\n"
" - '/lurch fp list': Displays the fingerprints of all your devices.\n"
" - '/lurch fp other': Displays the fingerprints of all of your conversation partner's devices.\n"
" - '/lurch status': Shows the OMEMO status of this conversation.\n"
" - '/lurch help': Displays this message.\n"
" - '/lurch uninstall': Uninstalls this device from OMEMO by removing its device ID from the devicelist.";
......@@ -114,6 +115,37 @@ void lurch_fp_show_print(int32_t err, const char * fp_printable, void * user_dat
g_free(msg);
}
void lurch_fp_print(int32_t err, GHashTable * id_fp_table, void * user_data_p) {
PurpleConversation * conv_p = (PurpleConversation *) user_data_p;
GString * msg = (void *) 0;
GList * key_list = (void *) 0;
const GList * curr_p = (void *) 0;
const char * fp = (void *) 0;
if (err) {
lurch_cmd_print_err(conv_p, "Failed to get the fingerprints. Check the debug log for details.");
return;
}
if (!id_fp_table) {
lurch_cmd_print(conv_p, "The devicelist is empty, so there is nothing to show!");
return;
}
msg = g_string_new("\n");
key_list = g_hash_table_get_keys(id_fp_table);
for (curr_p = key_list; curr_p; curr_p = curr_p->next) {
fp = (char *) g_hash_table_lookup(id_fp_table, curr_p->data);
g_string_append_printf(msg, "%i's fingerprint:\n%s\n", *((uint32_t *) curr_p->data), fp ? fp : "(no session)");
}
lurch_cmd_print(conv_p, msg->str);
g_string_free(msg, TRUE);
g_list_free(key_list);
}
void lurch_status_im_print(int32_t err, lurch_status_t status, void * user_data_p) {
PurpleConversation * conv_p = (PurpleConversation *) user_data_p;
const char * msg = (void *) 0;
......@@ -184,11 +216,19 @@ static void lurch_cmd_disable(PurpleConversation * conv_p) {
static void lurch_cmd_fp(PurpleConversation * conv_p, const char * arg) {
PurpleAccount * acc_p = purple_conversation_get_account(conv_p);
void * plugins_handle = purple_plugins_get_handle();
char * conv_bare_jid = jabber_get_bare_jid(purple_conversation_get_name(conv_p));
if (!g_strcmp0(arg, "show")) {
purple_signal_emit(purple_plugins_get_handle(), "lurch-fp-get", acc_p, lurch_fp_show_print, conv_p);
purple_signal_emit(plugins_handle, "lurch-fp-get", acc_p, lurch_fp_show_print, conv_p);
} else if (!g_strcmp0(arg, "list")) {
lurch_cmd_print(conv_p, "Your devices' fingerprints are:");
purple_signal_emit(plugins_handle, "lurch-fp-list", acc_p, lurch_fp_print, conv_p);
} else if (!g_strcmp0(arg, "other")) {
lurch_cmd_print(conv_p, "Your contact's devices' fingerprints are:");
purple_signal_emit(plugins_handle, "lurch-fp-other", acc_p, conv_bare_jid, lurch_fp_print, conv_p);
} else {
lurch_cmd_print(conv_p, "Valid arguments for 'fp' are 'show'.");
lurch_cmd_print(conv_p, "Valid arguments for 'fp' are 'show', 'list', and 'other'.");
}
}
......
......@@ -45,6 +45,6 @@ char * lurch_util_uname_get_db_fn(const char * uname, const char * which);
* Also useful for avoiding the smileys produced by ':d'...
*
* @param fp The fingerprint string as returned by purple_base16_encode_chunked
* @return A newly allocated string which contains the fingerprint in printable format, or NULL.
* @return A newly allocated string which contains the fingerprint in printable format, or NULL. g_free() when done.
*/
char * lurch_util_fp_get_printable(const char * fp);
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment