mirror of
https://git.jabber.space/devs/cproof.git
synced 2026-07-18 11:26:21 +00:00
@@ -2332,13 +2332,18 @@ static const struct cmd_t command_defs[] = {
|
||||
"/omemo clear_device_list",
|
||||
"/omemo qrcode")
|
||||
CMD_DESC(
|
||||
"OMEMO commands to manage keys, and perform encryption during chat sessions.")
|
||||
"OMEMO commands to manage keys, and perform encryption during chat sessions.\n"
|
||||
"The title bar will show the OMEMO session status:\n"
|
||||
"[OMEMO][trusted] - All active devices for the contact are trusted.\n"
|
||||
"[OMEMO][untrusted] - One or more active devices for the contact are untrusted.\n")
|
||||
CMD_ARGS(
|
||||
{ "gen", "Generate OMEMO cryptographic materials for current account." },
|
||||
{ "start [<contact>]", "Start an OMEMO session with contact, or current recipient if omitted." },
|
||||
{ "end", "End the current OMEMO session." },
|
||||
{ "log on|off", "Enable or disable plaintext logging of OMEMO encrypted messages." },
|
||||
{ "log redact", "Log OMEMO encrypted messages, but replace the contents with [redacted]." },
|
||||
{ "trust [<contact>] <fp>", "Trust a fingerprint for a contact, or current recipient if omitted. If all active devices are trusted, the title bar will show [trusted]. Otherwise, it will show [untrusted]." },
|
||||
{ "untrust [<contact>] <fp>","Untrust a fingerprint for a contact, or current recipient if omitted." },
|
||||
{ "fingerprint [<contact>]", "Show contact's fingerprints, or current recipient's if omitted." },
|
||||
{ "char <char>", "Set the character to be displayed next to OMEMO encrypted messages." },
|
||||
{ "trustmode manual", "Set the global OMEMO trust mode to manual, OMEMO keys has to be trusted manually." },
|
||||
|
||||
@@ -8479,6 +8479,7 @@ cmd_omemo_start(ProfWin* window, const char* const command, gchar** args)
|
||||
}
|
||||
|
||||
accounts_add_omemo_state(session_get_account_name(), chatwin->barejid, TRUE);
|
||||
win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "Initiating OMEMO session with %s...", chatwin->barejid);
|
||||
omemo_start_session(chatwin->barejid);
|
||||
chatwin->is_omemo = TRUE;
|
||||
} else if (window->type == WIN_MUC) {
|
||||
@@ -8493,6 +8494,7 @@ cmd_omemo_start(ProfWin* window, const char* const command, gchar** args)
|
||||
if (muc_anonymity_type(mucwin->roomjid) == MUC_ANONYMITY_TYPE_NONANONYMOUS
|
||||
&& muc_member_type(mucwin->roomjid) == MUC_MEMBER_TYPE_MEMBERS_ONLY) {
|
||||
accounts_add_omemo_state(session_get_account_name(), mucwin->roomjid, TRUE);
|
||||
win_println((ProfWin*)mucwin, THEME_DEFAULT, "!", "Initiating OMEMO session in %s...", mucwin->roomjid);
|
||||
omemo_start_muc_sessions(mucwin->roomjid);
|
||||
mucwin->is_omemo = TRUE;
|
||||
} else {
|
||||
@@ -8686,8 +8688,9 @@ cmd_omemo_fingerprint(ProfWin* window, const char* const command, gchar** args)
|
||||
for (GList* fingerprint = fingerprints; fingerprint != NULL; fingerprint = fingerprint->next) {
|
||||
auto_char char* formatted_fingerprint = omemo_format_fingerprint(fingerprint->data);
|
||||
gboolean trusted = omemo_is_trusted_identity(jid->barejid, fingerprint->data);
|
||||
gboolean active = omemo_is_device_active(jid->barejid, fingerprint->data);
|
||||
|
||||
win_println(window, THEME_DEFAULT, "-", "%s's OMEMO fingerprint: %s%s", jid->barejid, formatted_fingerprint, trusted ? " (trusted)" : "");
|
||||
win_println(window, THEME_DEFAULT, "-", "%s's OMEMO fingerprint: %s%s%s", jid->barejid, formatted_fingerprint, trusted ? " (trusted)" : " (untrusted)", active ? " (active)" : " (inactive)");
|
||||
}
|
||||
|
||||
g_list_free(fingerprints);
|
||||
|
||||
@@ -105,6 +105,7 @@ typedef struct omemo_context
|
||||
prof_keyfile_t knowndevices;
|
||||
GHashTable* known_devices;
|
||||
gboolean loaded;
|
||||
gboolean notifying;
|
||||
} omemo_context;
|
||||
|
||||
static omemo_context omemo_ctx;
|
||||
@@ -168,6 +169,8 @@ _omemo_finalize_identity_load(ProfAccount* account)
|
||||
|
||||
omemo_devicelist_subscribe();
|
||||
|
||||
omemo_ctx.notifying = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -254,6 +257,7 @@ omemo_on_connect(ProfAccount* account)
|
||||
signal_protocol_store_context_set_identity_key_store(omemo_ctx.store, &identity_key_store);
|
||||
|
||||
omemo_ctx.loaded = FALSE;
|
||||
omemo_ctx.notifying = FALSE;
|
||||
omemo_ctx.device_list = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)g_list_free);
|
||||
omemo_ctx.device_list_handler = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
|
||||
omemo_ctx.known_devices = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)g_hash_table_destroy);
|
||||
@@ -515,6 +519,40 @@ omemo_set_device_list(const char* const from, GList* device_list)
|
||||
log_debug("[OMEMO] Setting device list for %s", STR_MAYBE_NULL(from));
|
||||
auto_jid Jid* jid = jid_create(from ?: connection_get_fulljid());
|
||||
|
||||
if (omemo_ctx.notifying) {
|
||||
GList* old_list = g_hash_table_lookup(omemo_ctx.device_list, jid->barejid);
|
||||
GList* new_iter;
|
||||
for (new_iter = device_list; new_iter != NULL; new_iter = new_iter->next) {
|
||||
uint32_t dev_id = GPOINTER_TO_UINT(new_iter->data);
|
||||
gboolean found = FALSE;
|
||||
GList* old_iter;
|
||||
for (old_iter = old_list; old_iter != NULL; old_iter = old_iter->next) {
|
||||
if (GPOINTER_TO_UINT(old_iter->data) == dev_id) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (equals_our_barejid(jid->barejid)) {
|
||||
if (dev_id != omemo_ctx.device_id) {
|
||||
cons_show("New OMEMO device (ID: %u) added to your account.", dev_id);
|
||||
}
|
||||
} else {
|
||||
ProfChatWin* chatwin = wins_get_chat(jid->barejid);
|
||||
if (chatwin) {
|
||||
win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "New OMEMO device (ID: %u) found for %s.", dev_id, jid->barejid);
|
||||
} else {
|
||||
ProfMucWin* mucwin = wins_get_muc(jid->barejid);
|
||||
if (mucwin) {
|
||||
win_println((ProfWin*)mucwin, THEME_DEFAULT, "!", "New OMEMO device (ID: %u) found for %s.", dev_id, jid->barejid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_hash_table_insert(omemo_ctx.device_list, strdup(jid->barejid), device_list);
|
||||
|
||||
OmemoDeviceListHandler handler = g_hash_table_lookup(omemo_ctx.device_list_handler, jid->barejid);
|
||||
@@ -691,8 +729,30 @@ omemo_start_device_session(const char* const jid, uint32_t device_id,
|
||||
}
|
||||
|
||||
log_debug("[OMEMO] create session with %s device %d", jid, device_id);
|
||||
if (omemo_ctx.notifying) {
|
||||
ProfChatWin* chatwin = wins_get_chat(jid);
|
||||
if (chatwin) {
|
||||
win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "OMEMO session with %s (device %u) ready.", jid, device_id);
|
||||
} else {
|
||||
ProfMucWin* mucwin = wins_get_muc(jid);
|
||||
if (mucwin) {
|
||||
win_println((ProfWin*)mucwin, THEME_DEFAULT, "!", "OMEMO session with %s (device %u) ready.", jid, device_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_debug("[OMEMO] session with %s device %d exists", jid, device_id);
|
||||
if (omemo_ctx.notifying) {
|
||||
ProfChatWin* chatwin = wins_get_chat(jid);
|
||||
if (chatwin) {
|
||||
win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "OMEMO session with %s (device %u) already exists.", jid, device_id);
|
||||
} else {
|
||||
ProfMucWin* mucwin = wins_get_muc(jid);
|
||||
if (mucwin) {
|
||||
win_println((ProfWin*)mucwin, THEME_DEFAULT, "!", "OMEMO session with %s (device %u) already exists.", jid, device_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -837,10 +897,42 @@ omemo_on_message_send(ProfWin* win, const char* const message, gboolean request_
|
||||
// Don't send the message if no key could be encrypted.
|
||||
// (Since none of the recipients would be able to read the message.)
|
||||
if (keys == NULL) {
|
||||
win_println(win, THEME_ERROR, "!", "This message cannot be decrypted for any recipient.\n"
|
||||
"You should trust your recipients' device fingerprint(s) using \"/omemo trust FINGERPRINT\".\n"
|
||||
"It could also be that the key bundle of the recipient(s) have not been received. "
|
||||
"In this case, you could try \"omemo end\", \"omemo start\", and send the message again.");
|
||||
win_println(win, THEME_ERROR, "!", "This message cannot be encrypted for any recipient.");
|
||||
|
||||
// Check for untrusted fingerprints for each recipient
|
||||
GList* recipients = NULL;
|
||||
if (muc) {
|
||||
ProfMucWin* mucwin = (ProfMucWin*)win;
|
||||
GList* members = muc_members(mucwin->roomjid);
|
||||
GList* iter;
|
||||
for (iter = members; iter != NULL; iter = iter->next) {
|
||||
auto_jid Jid* jidp = jid_create(iter->data);
|
||||
recipients = g_list_append(recipients, strdup(jidp->barejid));
|
||||
}
|
||||
g_list_free(members);
|
||||
} else {
|
||||
ProfChatWin* chatwin = (ProfChatWin*)win;
|
||||
recipients = g_list_append(recipients, strdup(chatwin->barejid));
|
||||
}
|
||||
|
||||
GList* rec_iter;
|
||||
for (rec_iter = recipients; rec_iter != NULL; rec_iter = rec_iter->next) {
|
||||
GList* untrusted = omemo_get_jid_untrusted_fingerprints(rec_iter->data);
|
||||
if (untrusted) {
|
||||
win_println(win, THEME_ERROR, "!", "Untrusted OMEMO fingerprints for %s:", (char*)rec_iter->data);
|
||||
GList* fp_iter;
|
||||
for (fp_iter = untrusted; fp_iter != NULL; fp_iter = fp_iter->next) {
|
||||
char* formatted = omemo_format_fingerprint(fp_iter->data);
|
||||
win_println(win, THEME_ERROR, "!", " - %s", formatted);
|
||||
free(formatted);
|
||||
}
|
||||
win_println(win, THEME_ERROR, "!", "Use \"/omemo trust %s <fingerprint>\" to trust them.", (char*)rec_iter->data);
|
||||
g_list_free_full(untrusted, free);
|
||||
}
|
||||
}
|
||||
g_list_free_full(recipients, free);
|
||||
|
||||
win_println(win, THEME_ERROR, "!", "It could also be that key bundles have not been received. Try \"/omemo end\", then \"/omemo start\".");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -922,13 +1014,17 @@ out:
|
||||
char*
|
||||
omemo_on_message_recv(const char* const from_jid, uint32_t sid,
|
||||
const unsigned char* const iv, size_t iv_len, GList* keys,
|
||||
const unsigned char* const payload, size_t payload_len, gboolean muc, gboolean* trusted)
|
||||
const unsigned char* const payload, size_t payload_len, gboolean muc, gboolean* trusted, omemo_error_t* error)
|
||||
{
|
||||
unsigned char* plaintext = NULL;
|
||||
auto_jid Jid* sender = NULL;
|
||||
auto_jid Jid* from = jid_create(from_jid);
|
||||
|
||||
*error = OMEMO_ERR_NONE;
|
||||
|
||||
if (!from) {
|
||||
log_error("[OMEMO][RECV] Invalid jid %s", from_jid);
|
||||
*error = OMEMO_ERR_INVALID_JID;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -944,6 +1040,7 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid,
|
||||
|
||||
if (!key) {
|
||||
log_warning("[OMEMO][RECV] received a message with no corresponding key");
|
||||
*error = OMEMO_ERR_NO_KEY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -960,6 +1057,7 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid,
|
||||
g_list_free(roster);
|
||||
if (!sender) {
|
||||
log_warning("[OMEMO][RECV] cannot find MUC message sender fulljid");
|
||||
*error = OMEMO_ERR_MUC_SENDER_NOT_FOUND;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
@@ -977,6 +1075,7 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid,
|
||||
res = session_cipher_create(&cipher, omemo_ctx.store, &address, omemo_ctx.signal);
|
||||
if (res != 0) {
|
||||
log_error("[OMEMO][RECV] cannot create session cipher");
|
||||
*error = OMEMO_ERR_NO_SESSION;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1035,13 +1134,19 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid,
|
||||
|
||||
session_cipher_free(cipher);
|
||||
if (res != 0) {
|
||||
log_error("[OMEMO][RECV] cannot decrypt message key");
|
||||
log_error("[OMEMO][RECV] cannot decrypt message key: %d", res);
|
||||
if (!*trusted) {
|
||||
*error = OMEMO_ERR_NOT_TRUSTED;
|
||||
} else {
|
||||
*error = OMEMO_ERR_DECRYPT_FAILED;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (signal_buffer_len(plaintext_key) != AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH) {
|
||||
log_error("[OMEMO][RECV] invalid key length");
|
||||
signal_buffer_free(plaintext_key);
|
||||
*error = OMEMO_ERR_DECRYPT_FAILED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1054,6 +1159,7 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid,
|
||||
if (res != 0) {
|
||||
log_error("[OMEMO][RECV] cannot decrypt message: %s", gcry_strerror(res));
|
||||
free(plaintext);
|
||||
*error = OMEMO_ERR_DECRYPT_FAILED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1137,7 +1243,7 @@ omemo_is_trusted_identity(const char* const jid, const char* const fingerprint)
|
||||
signal_protocol_address address = {
|
||||
.name = jid,
|
||||
.name_len = strlen(jid),
|
||||
.device_id = GPOINTER_TO_INT(device_id),
|
||||
.device_id = GPOINTER_TO_UINT(device_id),
|
||||
};
|
||||
|
||||
size_t fingerprint_len;
|
||||
@@ -1147,7 +1253,7 @@ omemo_is_trusted_identity(const char* const jid, const char* const fingerprint)
|
||||
buffer = signal_buffer_append(buffer, fingerprint_raw, fingerprint_len);
|
||||
|
||||
gboolean trusted = is_trusted_identity(&address, signal_buffer_data(buffer), signal_buffer_len(buffer), &omemo_ctx.identity_key_store);
|
||||
log_debug("[OMEMO] Device trusted %s (%d): %d", jid, GPOINTER_TO_INT(device_id), trusted);
|
||||
log_debug("[OMEMO] Device trusted %s (%u): %d", jid, GPOINTER_TO_UINT(device_id), trusted);
|
||||
|
||||
free(fingerprint_raw);
|
||||
signal_buffer_free(buffer);
|
||||
@@ -1155,6 +1261,127 @@ omemo_is_trusted_identity(const char* const jid, const char* const fingerprint)
|
||||
return trusted;
|
||||
}
|
||||
|
||||
gboolean
|
||||
omemo_is_jid_trusted(const char* const jid)
|
||||
{
|
||||
if (!omemo_loaded()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GList* device_list = g_hash_table_lookup(omemo_ctx.device_list, jid);
|
||||
if (!device_list) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GList* device_id_iter;
|
||||
for (device_id_iter = device_list; device_id_iter != NULL; device_id_iter = device_id_iter->next) {
|
||||
uint32_t device_id = GPOINTER_TO_UINT(device_id_iter->data);
|
||||
if (device_id == omemo_ctx.device_id && equals_our_barejid(jid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GHashTable* known_identities = g_hash_table_lookup(omemo_ctx.known_devices, jid);
|
||||
if (!known_identities) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean found = FALSE;
|
||||
GList* fp_list = g_hash_table_get_keys(known_identities);
|
||||
GList* fp_iter;
|
||||
for (fp_iter = fp_list; fp_iter != NULL; fp_iter = fp_iter->next) {
|
||||
if (device_id == GPOINTER_TO_UINT(g_hash_table_lookup(known_identities, fp_iter->data))) {
|
||||
if (!omemo_is_trusted_identity(jid, fp_iter->data)) {
|
||||
g_list_free(fp_list);
|
||||
return FALSE;
|
||||
}
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_list_free(fp_list);
|
||||
|
||||
if (!found) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GList*
|
||||
omemo_get_jid_untrusted_fingerprints(const char* const jid)
|
||||
{
|
||||
if (!omemo_loaded()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GList* device_list = g_hash_table_lookup(omemo_ctx.device_list, jid);
|
||||
if (!device_list) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GList* untrusted_fps = NULL;
|
||||
GList* device_id_iter;
|
||||
for (device_id_iter = device_list; device_id_iter != NULL; device_id_iter = device_id_iter->next) {
|
||||
uint32_t device_id = GPOINTER_TO_UINT(device_id_iter->data);
|
||||
if (device_id == omemo_ctx.device_id && equals_our_barejid(jid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GHashTable* known_identities = g_hash_table_lookup(omemo_ctx.known_devices, jid);
|
||||
if (!known_identities) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GList* fp_list = g_hash_table_get_keys(known_identities);
|
||||
GList* fp_iter;
|
||||
for (fp_iter = fp_list; fp_iter != NULL; fp_iter = fp_iter->next) {
|
||||
if (device_id == GPOINTER_TO_UINT(g_hash_table_lookup(known_identities, fp_iter->data))) {
|
||||
if (!omemo_is_trusted_identity(jid, fp_iter->data)) {
|
||||
untrusted_fps = g_list_append(untrusted_fps, g_strdup(fp_iter->data));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_list_free(fp_list);
|
||||
}
|
||||
|
||||
return untrusted_fps;
|
||||
}
|
||||
|
||||
gboolean
|
||||
omemo_is_device_active(const char* const jid, const char* const fingerprint)
|
||||
{
|
||||
if (!omemo_loaded()) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GList* device_list = g_hash_table_lookup(omemo_ctx.device_list, jid);
|
||||
if (!device_list) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GHashTable* known_identities = g_hash_table_lookup(omemo_ctx.known_devices, jid);
|
||||
if (!known_identities) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void* device_id = g_hash_table_lookup(known_identities, fingerprint);
|
||||
if (!device_id) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
uint32_t dev_id = GPOINTER_TO_UINT(device_id);
|
||||
GList* iter;
|
||||
for (iter = device_list; iter != NULL; iter = iter->next) {
|
||||
if (GPOINTER_TO_UINT(iter->data) == dev_id) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static char*
|
||||
_omemo_fingerprint(ec_public_key* identity, gboolean formatted)
|
||||
{
|
||||
@@ -1697,6 +1924,27 @@ _cache_device_identity(const char* const jid, uint32_t device_id, ec_public_key*
|
||||
if (!fingerprint) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (omemo_ctx.notifying) {
|
||||
if (!g_hash_table_contains(known_identities, fingerprint)) {
|
||||
char* formatted = omemo_format_fingerprint(fingerprint);
|
||||
if (equals_our_barejid(jid)) {
|
||||
cons_show("New OMEMO fingerprint for your account: %s (ID: %u).", formatted, device_id);
|
||||
} else {
|
||||
ProfChatWin* chatwin = wins_get_chat(jid);
|
||||
if (chatwin) {
|
||||
win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "New OMEMO fingerprint for %s: %s (ID: %u).", jid, formatted, device_id);
|
||||
} else {
|
||||
ProfMucWin* mucwin = wins_get_muc(jid);
|
||||
if (mucwin) {
|
||||
win_println((ProfWin*)mucwin, THEME_DEFAULT, "!", "New OMEMO fingerprint for %s: %s (ID: %u).", jid, formatted, device_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(formatted);
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("[OMEMO] cache identity for %s:%d: %s", jid, device_id, fingerprint);
|
||||
g_hash_table_insert(known_identities, strdup(fingerprint), GINT_TO_POINTER(device_id));
|
||||
|
||||
|
||||
@@ -85,6 +85,9 @@ void omemo_trust(const char* const jid, const char* const fingerprint);
|
||||
void omemo_untrust(const char* const jid, const char* const fingerprint);
|
||||
GList* omemo_known_device_identities(const char* const jid);
|
||||
gboolean omemo_is_trusted_identity(const char* const jid, const char* const fingerprint);
|
||||
gboolean omemo_is_jid_trusted(const char* const jid);
|
||||
GList* omemo_get_jid_untrusted_fingerprints(const char* const jid);
|
||||
gboolean omemo_is_device_active(const char* const jid, const char* const fingerprint);
|
||||
char* omemo_fingerprint_autocomplete(const char* const search_str, gboolean previous, void* context);
|
||||
void omemo_fingerprint_autocomplete_reset(void);
|
||||
gboolean omemo_automatic_start(const char* const recipient);
|
||||
@@ -95,8 +98,9 @@ void omemo_start_muc_sessions(const char* const roomjid);
|
||||
void omemo_start_device_session(const char* const jid, uint32_t device_id, GList* prekeys, uint32_t signed_prekey_id, const unsigned char* const signed_prekey, size_t signed_prekey_len, const unsigned char* const signature, size_t signature_len, const unsigned char* const identity_key, size_t identity_key_len);
|
||||
|
||||
gboolean omemo_loaded(void);
|
||||
|
||||
char* omemo_on_message_send(ProfWin* win, const char* const message, gboolean request_receipt, gboolean muc, const char* const replace_id);
|
||||
char* omemo_on_message_recv(const char* const from, uint32_t sid, const unsigned char* const iv, size_t iv_len, GList* keys, const unsigned char* const payload, size_t payload_len, gboolean muc, gboolean* trusted);
|
||||
char* omemo_on_message_recv(const char* const from, uint32_t sid, const unsigned char* const iv, size_t iv_len, GList* keys, const unsigned char* const payload, size_t payload_len, gboolean muc, gboolean* trusted, omemo_error_t* error) __attribute__((nonnull(9, 10)));
|
||||
|
||||
char* omemo_encrypt_file(FILE* in, FILE* out, off_t file_size, int* gcry_res);
|
||||
gcry_error_t omemo_decrypt_file(FILE* in, FILE* out, off_t file_size, const char* fragment);
|
||||
|
||||
@@ -49,6 +49,9 @@
|
||||
#include "ui/window_list.h"
|
||||
#include "ui/window.h"
|
||||
#include "ui/screen.h"
|
||||
#ifdef HAVE_OMEMO
|
||||
#include "omemo/omemo.h"
|
||||
#endif
|
||||
#include "xmpp/roster_list.h"
|
||||
#include "xmpp/chat_session.h"
|
||||
|
||||
@@ -410,6 +413,10 @@ _show_muc_privacy(ProfMucWin* mucwin)
|
||||
{
|
||||
int bracket_attrs = theme_attrs(THEME_TITLE_BRACKET);
|
||||
int encrypted_attrs = theme_attrs(THEME_TITLE_ENCRYPTED);
|
||||
#ifdef HAVE_OMEMO
|
||||
int trusted_attrs = theme_attrs(THEME_TITLE_TRUSTED);
|
||||
int untrusted_attrs = theme_attrs(THEME_TITLE_UNTRUSTED);
|
||||
#endif
|
||||
|
||||
if (mucwin->is_omemo) {
|
||||
wprintw(win, " ");
|
||||
@@ -423,6 +430,32 @@ _show_muc_privacy(ProfMucWin* mucwin)
|
||||
wprintw(win, "]");
|
||||
wattroff(win, bracket_attrs);
|
||||
|
||||
#ifdef HAVE_OMEMO
|
||||
if (omemo_is_jid_trusted(mucwin->roomjid)) {
|
||||
wprintw(win, " ");
|
||||
wattron(win, bracket_attrs);
|
||||
wprintw(win, "[");
|
||||
wattroff(win, bracket_attrs);
|
||||
wattron(win, trusted_attrs);
|
||||
wprintw(win, "trusted");
|
||||
wattroff(win, trusted_attrs);
|
||||
wattron(win, bracket_attrs);
|
||||
wprintw(win, "]");
|
||||
wattroff(win, bracket_attrs);
|
||||
} else {
|
||||
wprintw(win, " ");
|
||||
wattron(win, bracket_attrs);
|
||||
wprintw(win, "[");
|
||||
wattroff(win, bracket_attrs);
|
||||
wattron(win, untrusted_attrs);
|
||||
wprintw(win, "untrusted");
|
||||
wattroff(win, untrusted_attrs);
|
||||
wattron(win, bracket_attrs);
|
||||
wprintw(win, "]");
|
||||
wattroff(win, bracket_attrs);
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -552,6 +585,32 @@ _show_privacy(ProfChatWin* chatwin)
|
||||
wprintw(win, "]");
|
||||
wattroff(win, bracket_attrs);
|
||||
|
||||
#ifdef HAVE_OMEMO
|
||||
if (omemo_is_jid_trusted(chatwin->barejid)) {
|
||||
wprintw(win, " ");
|
||||
wattron(win, bracket_attrs);
|
||||
wprintw(win, "[");
|
||||
wattroff(win, bracket_attrs);
|
||||
wattron(win, trusted_attrs);
|
||||
wprintw(win, "trusted");
|
||||
wattroff(win, trusted_attrs);
|
||||
wattron(win, bracket_attrs);
|
||||
wprintw(win, "]");
|
||||
wattroff(win, bracket_attrs);
|
||||
} else {
|
||||
wprintw(win, " ");
|
||||
wattron(win, bracket_attrs);
|
||||
wprintw(win, "[");
|
||||
wattroff(win, bracket_attrs);
|
||||
wattron(win, untrusted_attrs);
|
||||
wprintw(win, "untrusted");
|
||||
wattroff(win, untrusted_attrs);
|
||||
wattron(win, bracket_attrs);
|
||||
wprintw(win, "]");
|
||||
wattroff(win, bracket_attrs);
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -356,6 +356,7 @@ message_init(void)
|
||||
ProfMessage* message = g_new0(ProfMessage, 1);
|
||||
|
||||
message->enc = PROF_MSG_ENC_NONE;
|
||||
message->omemo_err = OMEMO_ERR_NONE;
|
||||
message->trusted = true;
|
||||
message->type = PROF_MSG_TYPE_UNINITIALIZED;
|
||||
|
||||
@@ -1110,8 +1111,29 @@ _handle_groupchat(xmpp_stanza_t* const stanza)
|
||||
|
||||
// check omemo encryption
|
||||
#ifdef HAVE_OMEMO
|
||||
message->plain = omemo_receive_message(stanza, &message->trusted);
|
||||
if (message->plain != NULL) {
|
||||
message->plain = omemo_receive_message(stanza, &message->trusted, &message->omemo_err);
|
||||
if (message->omemo_err != OMEMO_ERR_NONE) {
|
||||
message->enc = PROF_MSG_ENC_OMEMO;
|
||||
if (message->plain == NULL) {
|
||||
switch (message->omemo_err) {
|
||||
case OMEMO_ERR_NO_KEY:
|
||||
message->plain = g_strdup("OMEMO message received but no key for this device found.");
|
||||
break;
|
||||
case OMEMO_ERR_NOT_TRUSTED:
|
||||
message->plain = g_strdup("OMEMO message received but sender identity is untrusted.");
|
||||
break;
|
||||
case OMEMO_ERR_NO_SESSION:
|
||||
message->plain = g_strdup("OMEMO message received but no session found. Try '/omemo start'.");
|
||||
break;
|
||||
case OMEMO_ERR_DECRYPT_FAILED:
|
||||
message->plain = g_strdup("OMEMO message received but decryption failed.");
|
||||
break;
|
||||
default:
|
||||
message->plain = g_strdup("OMEMO message received but could not be decrypted.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (message->plain != NULL) {
|
||||
message->enc = PROF_MSG_ENC_OMEMO;
|
||||
}
|
||||
#endif
|
||||
@@ -1270,8 +1292,29 @@ _handle_muc_private_message(xmpp_stanza_t* const stanza)
|
||||
|
||||
// check omemo encryption
|
||||
#ifdef HAVE_OMEMO
|
||||
message->plain = omemo_receive_message(stanza, &message->trusted);
|
||||
if (message->plain != NULL) {
|
||||
message->plain = omemo_receive_message(stanza, &message->trusted, &message->omemo_err);
|
||||
if (message->omemo_err != OMEMO_ERR_NONE) {
|
||||
message->enc = PROF_MSG_ENC_OMEMO;
|
||||
if (message->plain == NULL) {
|
||||
switch (message->omemo_err) {
|
||||
case OMEMO_ERR_NO_KEY:
|
||||
message->plain = g_strdup("OMEMO message received but no key for this device found.");
|
||||
break;
|
||||
case OMEMO_ERR_NOT_TRUSTED:
|
||||
message->plain = g_strdup("OMEMO message received but sender identity is untrusted.");
|
||||
break;
|
||||
case OMEMO_ERR_NO_SESSION:
|
||||
message->plain = g_strdup("OMEMO message received but no session found. Try '/omemo start'.");
|
||||
break;
|
||||
case OMEMO_ERR_DECRYPT_FAILED:
|
||||
message->plain = g_strdup("OMEMO message received but decryption failed.");
|
||||
break;
|
||||
default:
|
||||
message->plain = g_strdup("OMEMO message received but could not be decrypted.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (message->plain != NULL) {
|
||||
message->enc = PROF_MSG_ENC_OMEMO;
|
||||
}
|
||||
#endif
|
||||
@@ -1437,8 +1480,29 @@ _handle_chat(xmpp_stanza_t* const stanza, gboolean is_mam, gboolean is_carbon, c
|
||||
|
||||
#ifdef HAVE_OMEMO
|
||||
// check omemo encryption
|
||||
message->plain = omemo_receive_message(stanza, &message->trusted);
|
||||
if (message->plain != NULL) {
|
||||
message->plain = omemo_receive_message(stanza, &message->trusted, &message->omemo_err);
|
||||
if (message->omemo_err != OMEMO_ERR_NONE) {
|
||||
message->enc = PROF_MSG_ENC_OMEMO;
|
||||
if (message->plain == NULL) {
|
||||
switch (message->omemo_err) {
|
||||
case OMEMO_ERR_NO_KEY:
|
||||
message->plain = g_strdup("OMEMO message received but no key for this device found.");
|
||||
break;
|
||||
case OMEMO_ERR_NOT_TRUSTED:
|
||||
message->plain = g_strdup("OMEMO message received but sender identity is untrusted.");
|
||||
break;
|
||||
case OMEMO_ERR_NO_SESSION:
|
||||
message->plain = g_strdup("OMEMO message received but no session found. Try '/omemo start'.");
|
||||
break;
|
||||
case OMEMO_ERR_DECRYPT_FAILED:
|
||||
message->plain = g_strdup("OMEMO message received but decryption failed.");
|
||||
break;
|
||||
default:
|
||||
message->plain = g_strdup("OMEMO message received but could not be decrypted.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (message->plain != NULL) {
|
||||
message->enc = PROF_MSG_ENC_OMEMO;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -350,7 +350,7 @@ out:
|
||||
}
|
||||
|
||||
char*
|
||||
omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted)
|
||||
omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_error_t* error)
|
||||
{
|
||||
char* plaintext = NULL;
|
||||
const char* type = xmpp_stanza_get_type(stanza);
|
||||
@@ -360,6 +360,8 @@ omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted)
|
||||
char* iv_text = NULL;
|
||||
char* payload_text = NULL;
|
||||
|
||||
*error = OMEMO_ERR_NONE;
|
||||
|
||||
xmpp_stanza_t* encrypted = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_OMEMO);
|
||||
if (!encrypted) {
|
||||
return NULL;
|
||||
@@ -367,40 +369,48 @@ omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted)
|
||||
|
||||
xmpp_stanza_t* header = xmpp_stanza_get_child_by_name(encrypted, "header");
|
||||
if (!header) {
|
||||
*error = OMEMO_ERR_OTHER;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* sid_text = xmpp_stanza_get_attribute(header, "sid");
|
||||
if (!sid_text) {
|
||||
*error = OMEMO_ERR_OTHER;
|
||||
return NULL;
|
||||
}
|
||||
uint32_t sid = strtoul(sid_text, NULL, 10);
|
||||
|
||||
xmpp_stanza_t* iv = xmpp_stanza_get_child_by_name(header, "iv");
|
||||
if (!iv) {
|
||||
*error = OMEMO_ERR_OTHER;
|
||||
return NULL;
|
||||
}
|
||||
iv_text = xmpp_stanza_get_text(iv);
|
||||
if (!iv_text) {
|
||||
*error = OMEMO_ERR_OTHER;
|
||||
return NULL;
|
||||
}
|
||||
size_t iv_len;
|
||||
iv_raw = g_base64_decode(iv_text, &iv_len);
|
||||
if (!iv_raw) {
|
||||
*error = OMEMO_ERR_OTHER;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xmpp_stanza_t* payload = xmpp_stanza_get_child_by_name(encrypted, "payload");
|
||||
if (!payload) {
|
||||
*error = OMEMO_ERR_OTHER;
|
||||
goto quit;
|
||||
}
|
||||
payload_text = xmpp_stanza_get_text(payload);
|
||||
if (!payload_text) {
|
||||
*error = OMEMO_ERR_OTHER;
|
||||
goto quit;
|
||||
}
|
||||
size_t payload_len;
|
||||
payload_raw = g_base64_decode(payload_text, &payload_len);
|
||||
if (!payload_raw) {
|
||||
*error = OMEMO_ERR_OTHER;
|
||||
goto quit;
|
||||
}
|
||||
|
||||
@@ -439,7 +449,7 @@ omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted)
|
||||
|
||||
plaintext = omemo_on_message_recv(from, sid, iv_raw, iv_len,
|
||||
keys, payload_raw, payload_len,
|
||||
g_strcmp0(type, STANZA_TYPE_GROUPCHAT) == 0, trusted);
|
||||
g_strcmp0(type, STANZA_TYPE_GROUPCHAT) == 0, trusted, error);
|
||||
|
||||
if (keys) {
|
||||
g_list_free_full(keys, (GDestroyNotify)omemo_key_free);
|
||||
|
||||
@@ -44,4 +44,5 @@ void omemo_devicelist_request(const char* const jid);
|
||||
void omemo_bundle_publish(gboolean first);
|
||||
void omemo_bundle_request(const char* const jid, uint32_t device_id, ProfIqCallback func, ProfIqFreeCallback free_func, void* userdata);
|
||||
int omemo_start_device_session_handle_bundle(xmpp_stanza_t* const stanza, void* const userdata);
|
||||
char* omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted);
|
||||
|
||||
char* omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_error_t* error) __attribute__((nonnull(2, 3)));
|
||||
|
||||
@@ -150,6 +150,17 @@ typedef enum {
|
||||
PROF_MSG_TYPE_MUCPM
|
||||
} prof_msg_type_t;
|
||||
|
||||
typedef enum {
|
||||
OMEMO_ERR_NONE = 0,
|
||||
OMEMO_ERR_NO_KEY,
|
||||
OMEMO_ERR_NOT_TRUSTED,
|
||||
OMEMO_ERR_NO_SESSION,
|
||||
OMEMO_ERR_DECRYPT_FAILED,
|
||||
OMEMO_ERR_INVALID_JID,
|
||||
OMEMO_ERR_MUC_SENDER_NOT_FOUND,
|
||||
OMEMO_ERR_OTHER
|
||||
} omemo_error_t;
|
||||
|
||||
typedef struct prof_message_t
|
||||
{
|
||||
Jid* from_jid;
|
||||
@@ -172,6 +183,7 @@ typedef struct prof_message_t
|
||||
char* plain;
|
||||
GDateTime* timestamp;
|
||||
prof_enc_t enc;
|
||||
omemo_error_t omemo_err;
|
||||
gboolean trusted;
|
||||
gboolean is_mam;
|
||||
prof_msg_type_t type;
|
||||
|
||||
@@ -42,12 +42,30 @@ omemo_is_trusted_identity(const char* const jid, const char* const fingerprint)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
omemo_is_jid_trusted(const char* const jid)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GList*
|
||||
omemo_get_jid_untrusted_fingerprints(const char* const jid)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GList*
|
||||
omemo_known_device_identities(const char* const jid)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
omemo_is_device_active(const char* const jid, const char* const fingerprint)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
omemo_loaded(void)
|
||||
{
|
||||
@@ -111,6 +129,23 @@ omemo_encrypt_file(FILE* in, FILE* out, off_t file_size, int* gcry_res)
|
||||
};
|
||||
void omemo_free(void* a) {};
|
||||
|
||||
char*
|
||||
omemo_on_message_recv(const char* const from, uint32_t sid,
|
||||
const unsigned char* const iv, size_t iv_len,
|
||||
GList* keys, const unsigned char* const payload,
|
||||
size_t payload_len, gboolean muc, gboolean* trusted, omemo_error_t* error)
|
||||
{
|
||||
*error = OMEMO_ERR_NONE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char*
|
||||
omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_error_t* error)
|
||||
{
|
||||
*error = OMEMO_ERR_NONE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
omemo_device_id()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user