mirror of
https://github.com/profanity-im/profanity.git
synced 2024-12-04 14:46:46 -05:00
Feature request - XEP-0373: OpenPGP for XMPP (OX)
Basic implementation of XEP-0373: OpenPGP for XMPP. https://xmpp.org/extensions/xep-0373.html Command /ox Issue: #1331
This commit is contained in:
parent
3afd854dc8
commit
2c94ee5a88
78
docs/profanity-ox.md
Normal file
78
docs/profanity-ox.md
Normal file
@ -0,0 +1,78 @@
|
||||
# Profanity - OpenPGP for XMPP
|
||||
|
||||
Implementation of XEP-0373 - OpenPGP for XMPP (OX) in profanity.
|
||||
|
||||
## Overview
|
||||
The current version (2020-05-23) of profanity provides *XEP-0027: Current Jabber
|
||||
OpenPGP Usage* via the `/pgp` command. This XEP is *Obsolete*. We should
|
||||
implement *XEP-0373 - OpenPGP for XMPP (OX)* in profanity.
|
||||
|
||||
## pgp
|
||||
|
||||
```
|
||||
14:37:52 - Synopsis
|
||||
14:37:52 - /pgp libver
|
||||
14:37:52 - /pgp keys
|
||||
14:37:52 - /pgp contacts
|
||||
14:37:52 - /pgp setkey <contact> <keyid>
|
||||
14:37:52 - /pgp start [<contact>]
|
||||
14:37:52 - /pgp end
|
||||
14:37:52 - /pgp log on|off|redact
|
||||
14:37:52 - /pgp char <char>
|
||||
14:37:52 -
|
||||
14:37:52 - Description
|
||||
14:37:52 - Open PGP commands to manage keys, and perform PGP encryption during chat sessions. See the /account command to set your own PGP key.
|
||||
14:37:52 -
|
||||
14:37:52 - Arguments
|
||||
14:37:52 - libver : Show which version of the libgpgme library is being used.
|
||||
14:37:52 - keys : List all keys known to the system.
|
||||
14:37:52 - contacts : Show contacts with assigned public keys.
|
||||
14:37:52 - setkey <contact> <keyid> : Manually associate a contact with a public key.
|
||||
14:37:52 - start [<contact>] : Start PGP encrypted chat, current contact will be used if not specified.
|
||||
14:37:52 - end : End PGP encrypted chat with the current recipient.
|
||||
14:37:52 - log on|off : Enable or disable plaintext logging of PGP encrypted messages.
|
||||
14:37:52 - log redact : Log PGP encrypted messages, but replace the contents with [redacted]. This is the default.
|
||||
14:37:52 - char <char> : Set the character to be displayed next to PGP encrypted messages.
|
||||
```
|
||||
## OX
|
||||
We should implement the `/ox` command which can be used for XEP-0373 instead of
|
||||
XEP-0027.
|
||||
|
||||
```
|
||||
/ox keys - List all public keys known to the system (gnupg's keyring)
|
||||
/ox contacts - Shows contacts with an assigned public key.
|
||||
```
|
||||
|
||||
The `keys` command will list all public keys of gnupg's Keyring, independent if
|
||||
the key is in use for XMPP or not.
|
||||
|
||||
In profanity we are going to implement the key lookup with a XMPP-URI as OpenPGP
|
||||
User-ID. An OpenPGP public key can only be used, if the owner of the public key
|
||||
created an User-ID with the XMPP-URI as Name. https://xmpp.org/extensions/xep-0373.html#openpgp-user-ids
|
||||
It's not required and possible to assign a contact to an public key.
|
||||
|
||||
```
|
||||
sec rsa3072 2020-05-01 [SC] [verfällt: 2022-05-01]
|
||||
7FA1EB8644BAC07E7F18E7C9F121E6A6F3A0C7A5
|
||||
uid [ ultimativ ] Doctor Snuggles <doctor.snuggles@domain.tld>
|
||||
uid [ ultimativ ] xmpp:doctor.snuggles@domain.tld
|
||||
ssb rsa3072 2020-05-01 [E] [verfällt: 2022-05-01]
|
||||
```
|
||||
|
||||
The `contacts` command will show all contacts of the roster with a public key in
|
||||
the keyring, if there is a xmpp user-id within the public key.
|
||||
|
||||
OX provides the elements: `<signcrypt/>`, `<sign/>` and `<crypt/>`. Profanity
|
||||
implements signcrypt, only.
|
||||
|
||||
|
||||
## Keys command
|
||||
The command `keys` is independent of the XEP. Should we move common commands
|
||||
(e.g. /pgp keys /ox keys) to /openpgp which will will be the function which are
|
||||
related to gnupg itself.
|
||||
|
||||
## Appendix
|
||||
|
||||
* https://xmpp.org/extensions/xep-0373.html - 0.4.0 (2018-07-30)
|
||||
|
||||
|
@ -78,6 +78,7 @@ static char* _otr_autocomplete(ProfWin *window, const char *const input, gboolea
|
||||
#endif
|
||||
#ifdef HAVE_LIBGPGME
|
||||
static char* _pgp_autocomplete(ProfWin *window, const char *const input, gboolean previous);
|
||||
static char* _ox_autocomplete(ProfWin *window, const char *const input, gboolean previous);
|
||||
#endif
|
||||
#ifdef HAVE_OMEMO
|
||||
static char* _omemo_autocomplete(ProfWin *window, const char *const input, gboolean previous);
|
||||
@ -224,6 +225,9 @@ static Autocomplete receipts_ac;
|
||||
static Autocomplete pgp_ac;
|
||||
static Autocomplete pgp_log_ac;
|
||||
static Autocomplete pgp_sendfile_ac;
|
||||
static Autocomplete ox_ac;
|
||||
static Autocomplete ox_log_ac;
|
||||
static Autocomplete ox_sendfile_ac;
|
||||
#endif
|
||||
static Autocomplete tls_ac;
|
||||
static Autocomplete titlebar_ac;
|
||||
@ -261,6 +265,13 @@ static Autocomplete correction_ac;
|
||||
static Autocomplete avatar_ac;
|
||||
static Autocomplete executable_ac;
|
||||
|
||||
/*!
|
||||
* \brief Initialization of auto completion for commands.
|
||||
*
|
||||
* This function implements the auto completion for profanity's commands.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
cmd_ac_init(void)
|
||||
{
|
||||
@ -842,6 +853,29 @@ cmd_ac_init(void)
|
||||
pgp_sendfile_ac = autocomplete_new();
|
||||
autocomplete_add(pgp_sendfile_ac, "on");
|
||||
autocomplete_add(pgp_sendfile_ac, "off");
|
||||
|
||||
// XEP-0373: OX
|
||||
ox_ac = autocomplete_new();
|
||||
autocomplete_add(ox_ac, "keys");
|
||||
autocomplete_add(ox_ac, "contacts");
|
||||
autocomplete_add(ox_ac, "start");
|
||||
autocomplete_add(ox_ac, "end");
|
||||
autocomplete_add(ox_ac, "log");
|
||||
autocomplete_add(ox_ac, "char");
|
||||
autocomplete_add(ox_ac, "sendfile");
|
||||
autocomplete_add(ox_ac, "announce");
|
||||
autocomplete_add(ox_ac, "discover");
|
||||
autocomplete_add(ox_ac, "request");
|
||||
|
||||
pgp_log_ac = autocomplete_new();
|
||||
autocomplete_add(ox_log_ac, "on");
|
||||
autocomplete_add(ox_log_ac, "off");
|
||||
autocomplete_add(ox_log_ac, "redact");
|
||||
|
||||
pgp_sendfile_ac = autocomplete_new();
|
||||
autocomplete_add(ox_sendfile_ac, "on");
|
||||
autocomplete_add(ox_sendfile_ac, "off");
|
||||
|
||||
#endif
|
||||
|
||||
tls_ac = autocomplete_new();
|
||||
@ -1707,6 +1741,7 @@ _cmd_ac_complete_params(ProfWin *window, const char *const input, gboolean previ
|
||||
#endif
|
||||
#ifdef HAVE_LIBGPGME
|
||||
g_hash_table_insert(ac_funcs, "/pgp", _pgp_autocomplete);
|
||||
g_hash_table_insert(ac_funcs, "/ox", _ox_autocomplete);
|
||||
#endif
|
||||
#ifdef HAVE_OMEMO
|
||||
g_hash_table_insert(ac_funcs, "/omemo", _omemo_autocomplete);
|
||||
@ -2420,6 +2455,68 @@ _pgp_autocomplete(ProfWin *window, const char *const input, gboolean previous)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Auto completion for XEP-0373: OpenPGP for XMPP command.
|
||||
*
|
||||
*
|
||||
*/
|
||||
static char*
|
||||
_ox_autocomplete(ProfWin *window, const char *const input, gboolean previous)
|
||||
{
|
||||
char *found = NULL;
|
||||
|
||||
jabber_conn_status_t conn_status = connection_get_status();
|
||||
|
||||
if (conn_status == JABBER_CONNECTED) {
|
||||
found = autocomplete_param_with_func(input, "/ox start", roster_contact_autocomplete, previous, NULL);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
found = autocomplete_param_with_ac(input, "/ox log", ox_log_ac, TRUE, previous);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
|
||||
found = autocomplete_param_with_ac(input, "/ox sendfile", ox_sendfile_ac, TRUE, previous);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
|
||||
gboolean result;
|
||||
gchar **args = parse_args(input, 2, 3, &result);
|
||||
if ((strncmp(input, "/ox", 4) == 0) && (result == TRUE)) {
|
||||
GString *beginning = g_string_new("/ox ");
|
||||
g_string_append(beginning, args[0]);
|
||||
if (args[1]) {
|
||||
g_string_append(beginning, " ");
|
||||
g_string_append(beginning, args[1]);
|
||||
}
|
||||
found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key, previous, NULL);
|
||||
g_string_free(beginning, TRUE);
|
||||
if (found) {
|
||||
g_strfreev(args);
|
||||
return found;
|
||||
}
|
||||
}
|
||||
g_strfreev(args);
|
||||
|
||||
if (conn_status == JABBER_CONNECTED) {
|
||||
found = autocomplete_param_with_func(input, "/ox setkey", roster_barejid_autocomplete, previous, NULL);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
found = autocomplete_param_with_ac(input, "/ox", ox_ac, TRUE, previous);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OMEMO
|
||||
|
@ -1691,6 +1691,48 @@ static struct cmd_t command_defs[] =
|
||||
"/pgp char P")
|
||||
},
|
||||
|
||||
// XEP-0373: OpenPGP for XMPP
|
||||
#ifdef HAVE_LIBGPGME
|
||||
{ "/ox",
|
||||
parse_args, 1, 3, NULL,
|
||||
CMD_NOSUBFUNCS
|
||||
CMD_MAINFUNC(cmd_ox)
|
||||
CMD_TAGS(
|
||||
CMD_TAG_CHAT,
|
||||
CMD_TAG_UI)
|
||||
CMD_SYN(
|
||||
"/ox keys",
|
||||
"/ox contacts",
|
||||
"/ox start [<contact>]",
|
||||
"/ox end",
|
||||
"/ox log on|off|redact",
|
||||
"/ox char <char>",
|
||||
"/ox sendfile on|off",
|
||||
"/ox announce <file>",
|
||||
"/ox discover",
|
||||
"/ox request <jid>")
|
||||
CMD_DESC(
|
||||
"OpenPGP (OX) commands to manage keys, and perform PGP encryption during chat sessions. ")
|
||||
CMD_ARGS(
|
||||
{ "keys", "List all keys known to the system." },
|
||||
{ "contacts", "Show contacts with assigned public keys." },
|
||||
{ "start [<contact>]", "Start PGP encrypted chat, current contact will be used if not specified." },
|
||||
{ "end", "End PGP encrypted chat with the current recipient." },
|
||||
{ "log on|off", "Enable or disable plaintext logging of PGP encrypted messages." },
|
||||
{ "log redact", "Log PGP encrypted messages, but replace the contents with [redacted]. This is the default." },
|
||||
{ "char <char>", "Set the character to be displayed next to PGP encrypted messages." },
|
||||
{ "announce <file>", "Announce a public key by pushing it on the XMPP Server"},
|
||||
{ "discover <jid>", "Discover public keys of a jid "},
|
||||
{ "request <jid>", "Request public keys"},
|
||||
{ "sendfile on|off", "Allow /sendfile to send unencrypted files while otherwise using PGP."})
|
||||
CMD_EXAMPLES(
|
||||
"/ox log off",
|
||||
"/ox start odin@valhalla.edda",
|
||||
"/ox end",
|
||||
"/ox char X")
|
||||
},
|
||||
#endif // HAVE_LIBGPGME
|
||||
|
||||
{ "/otr",
|
||||
parse_args, 1, 3, NULL,
|
||||
CMD_SUBFUNCS(
|
||||
|
@ -7418,6 +7418,169 @@ cmd_pgp(ProfWin *window, const char *const command, gchar **args)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBGPGME
|
||||
|
||||
/*!
|
||||
* \brief Command for XEP-0373: OpenPGP for XMPP
|
||||
*
|
||||
*/
|
||||
|
||||
gboolean
|
||||
cmd_ox(ProfWin *window, const char *const command, gchar **args)
|
||||
{
|
||||
if (args[0] == NULL) {
|
||||
cons_bad_cmd_usage(command);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// The '/ox keys' command - same like in pgp
|
||||
// Should we move this to a common command
|
||||
// e.g. '/openpgp keys'?.
|
||||
else if (g_strcmp0(args[0], "keys") == 0) {
|
||||
GHashTable *keys = p_gpg_list_keys();
|
||||
if (!keys || g_hash_table_size(keys) == 0) {
|
||||
cons_show("No keys found");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cons_show("OpenPGP keys:");
|
||||
GList *keylist = g_hash_table_get_keys(keys);
|
||||
GList *curr = keylist;
|
||||
while (curr) {
|
||||
ProfPGPKey *key = g_hash_table_lookup(keys, curr->data);
|
||||
cons_show(" %s", key->name);
|
||||
cons_show(" ID : %s", key->id);
|
||||
char *format_fp = p_gpg_format_fp_str(key->fp);
|
||||
cons_show(" Fingerprint : %s", format_fp);
|
||||
free(format_fp);
|
||||
if (key->secret) {
|
||||
cons_show(" Type : PUBLIC, PRIVATE");
|
||||
} else {
|
||||
cons_show(" Type : PUBLIC");
|
||||
}
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(keylist);
|
||||
p_gpg_free_keys(keys);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
else if (g_strcmp0(args[0], "contacts") == 0) {
|
||||
GHashTable *keys = ox_gpg_public_keys();
|
||||
cons_show("OpenPGP keys:");
|
||||
GList *keylist = g_hash_table_get_keys(keys);
|
||||
GList *curr = keylist;
|
||||
|
||||
|
||||
GSList *roster_list = NULL;
|
||||
jabber_conn_status_t conn_status = connection_get_status();
|
||||
if (conn_status != JABBER_CONNECTED) {
|
||||
cons_show("You are not currently connected.");
|
||||
} else {
|
||||
roster_list = roster_get_contacts(ROSTER_ORD_NAME);
|
||||
}
|
||||
|
||||
while (curr) {
|
||||
ProfPGPKey *key = g_hash_table_lookup(keys, curr->data);
|
||||
PContact contact = NULL;
|
||||
if (roster_list) {
|
||||
GSList *curr_c = roster_list;
|
||||
while ( !contact && curr_c){
|
||||
contact = curr_c->data;
|
||||
const char *jid = p_contact_barejid(contact);
|
||||
GString* xmppuri = g_string_new("xmpp:");
|
||||
g_string_append(xmppuri, jid);
|
||||
if( g_strcmp0(key->name, xmppuri->str)) {
|
||||
contact = NULL;
|
||||
}
|
||||
curr_c = g_slist_next(curr_c);
|
||||
}
|
||||
}
|
||||
|
||||
if(contact) {
|
||||
cons_show("%s - %s", key->fp, key->name);
|
||||
} else {
|
||||
cons_show("%s - %s (not in roster)", key->fp, key->name);
|
||||
}
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
|
||||
} else if (g_strcmp0(args[0], "start") == 0) {
|
||||
jabber_conn_status_t conn_status = connection_get_status();
|
||||
if (conn_status != JABBER_CONNECTED) {
|
||||
cons_show("You must be connected to start OX encrpytion.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (window->type != WIN_CHAT && args[1] == NULL) {
|
||||
cons_show("You must be in a regular chat window to start OX encrpytion.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ProfChatWin *chatwin = NULL;
|
||||
|
||||
if (args[1]) {
|
||||
char *contact = args[1];
|
||||
char *barejid = roster_barejid_from_name(contact);
|
||||
if (barejid == NULL) {
|
||||
barejid = contact;
|
||||
}
|
||||
|
||||
chatwin = wins_get_chat(barejid);
|
||||
if (!chatwin) {
|
||||
chatwin = chatwin_new(barejid);
|
||||
}
|
||||
ui_focus_win((ProfWin*)chatwin);
|
||||
} else {
|
||||
chatwin = (ProfChatWin*)window;
|
||||
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
|
||||
}
|
||||
|
||||
if (chatwin->is_otr) {
|
||||
win_println(window, THEME_DEFAULT, "!", "You must end the OTR session to start OX encryption.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (chatwin->pgp_send) {
|
||||
win_println(window, THEME_DEFAULT, "!", "You must end the PGP session to start OX encryption.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (chatwin->is_ox) {
|
||||
win_println(window, THEME_DEFAULT, "!", "You have already started OX encryption.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ProfAccount *account = accounts_get_account(session_get_account_name());
|
||||
|
||||
if ( !ox_is_private_key_available(account->jid) ) {
|
||||
win_println(window, THEME_DEFAULT, "!", "No private OpenPGP found, cannot start OX encryption.");
|
||||
account_free(account);
|
||||
return TRUE;
|
||||
}
|
||||
account_free(account);
|
||||
|
||||
if (!ox_is_public_key_available(chatwin->barejid)) {
|
||||
win_println(window, THEME_DEFAULT, "!", "No OX-OpenPGP key found for %s.", chatwin->barejid);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
chatwin->is_ox = TRUE;
|
||||
win_println(window, THEME_DEFAULT, "!", "OX encryption enabled.");
|
||||
return TRUE;
|
||||
} else if (g_strcmp0(args[0], "push") == 0) {
|
||||
if( args[1] ) {
|
||||
cons_show("Push file...%s ", args[1] );
|
||||
} else {
|
||||
cons_show("Filename is required");
|
||||
}
|
||||
} else {
|
||||
cons_show("OX not implemented");
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#endif // HAVE_LIBGPGME
|
||||
|
||||
gboolean
|
||||
cmd_otr_char(ProfWin *window, const char *const command, gchar **args)
|
||||
{
|
||||
|
@ -107,6 +107,9 @@ gboolean cmd_msg(ProfWin *window, const char *const command, gchar **args);
|
||||
gboolean cmd_nick(ProfWin *window, const char *const command, gchar **args);
|
||||
gboolean cmd_notify(ProfWin *window, const char *const command, gchar **args);
|
||||
gboolean cmd_pgp(ProfWin *window, const char *const command, gchar **args);
|
||||
#ifdef HAVE_LIBGPGME
|
||||
gboolean cmd_ox(ProfWin *window, const char *const command, gchar **args);
|
||||
#endif // HAVE_LIBGPGME
|
||||
gboolean cmd_outtype(ProfWin *window, const char *const command, gchar **args);
|
||||
gboolean cmd_prefs(ProfWin *window, const char *const command, gchar **args);
|
||||
gboolean cmd_priority(ProfWin *window, const char *const command, gchar **args);
|
||||
|
@ -62,6 +62,7 @@
|
||||
#define PREF_GROUP_OTR "otr"
|
||||
#define PREF_GROUP_PGP "pgp"
|
||||
#define PREF_GROUP_OMEMO "omemo"
|
||||
#define PREF_GROUP_OX "ox"
|
||||
#define PREF_GROUP_MUC "muc"
|
||||
#define PREF_GROUP_PLUGINS "plugins"
|
||||
|
||||
@ -942,6 +943,18 @@ prefs_set_pgp_char(char *ch)
|
||||
return _prefs_set_encryption_char(ch, PREF_GROUP_PGP, "pgp.char");
|
||||
}
|
||||
|
||||
char*
|
||||
prefs_get_ox_char(void)
|
||||
{
|
||||
return _prefs_get_encryption_char("%", PREF_GROUP_OX, "ox.char");
|
||||
}
|
||||
|
||||
gboolean
|
||||
prefs_set_ox_char(char *ch)
|
||||
{
|
||||
return _prefs_set_encryption_char(ch, PREF_GROUP_OX, "ox.char");
|
||||
}
|
||||
|
||||
char*
|
||||
prefs_get_omemo_char(void)
|
||||
{
|
||||
|
@ -244,6 +244,9 @@ char* prefs_get_pgp_char(void);
|
||||
gboolean prefs_set_pgp_char(char *ch);
|
||||
char* prefs_get_omemo_char(void);
|
||||
gboolean prefs_set_omemo_char(char *ch);
|
||||
// XEP-0373: OpenPGP for XMPP
|
||||
char* prefs_get_ox_char(void);
|
||||
gboolean prefs_set_ox_char(char *ch);
|
||||
|
||||
char prefs_get_roster_header_char(void);
|
||||
void prefs_set_roster_header_char(char ch);
|
||||
|
@ -288,6 +288,8 @@ static prof_msg_type_t _get_message_type_type(const char *const type) {
|
||||
|
||||
static const char* _get_message_enc_str(prof_enc_t enc) {
|
||||
switch (enc) {
|
||||
case PROF_MSG_ENC_OX:
|
||||
return "ox";
|
||||
case PROF_MSG_ENC_PGP:
|
||||
return "pgp";
|
||||
case PROF_MSG_ENC_OTR:
|
||||
@ -298,7 +300,7 @@ static const char* _get_message_enc_str(prof_enc_t enc) {
|
||||
return "none";
|
||||
}
|
||||
|
||||
return "none";
|
||||
return "none"; // do not return none - return NULL
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -138,6 +138,15 @@ cl_ev_send_msg_correct(ProfChatWin *chatwin, const char *const msg, const char *
|
||||
log_database_add_outgoing_chat(id, chatwin->barejid, plugin_msg, replace_id, PROF_MSG_ENC_OMEMO);
|
||||
chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_OMEMO, request_receipt, replace_id);
|
||||
free(id);
|
||||
#endif
|
||||
} else if (chatwin->is_ox) {
|
||||
#ifdef HAVE_LIBGPGME
|
||||
// XEP-0373: OpenPGP for XMPP
|
||||
char *id = message_send_chat_ox(chatwin->barejid, plugin_msg, request_receipt, replace_id);
|
||||
chat_log_pgp_msg_out(chatwin->barejid, plugin_msg, NULL);
|
||||
log_database_add_outgoing_chat(id, chatwin->barejid, plugin_msg, replace_id, PROF_MSG_ENC_OX);
|
||||
chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_OX, request_receipt, replace_id);
|
||||
free(id);
|
||||
#endif
|
||||
} else if (chatwin->pgp_send) {
|
||||
#ifdef HAVE_LIBGPGME
|
||||
|
@ -516,6 +516,22 @@ _sv_ev_incoming_pgp(ProfChatWin *chatwin, gboolean new_win, ProfMessage *message
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
_sv_ev_incoming_ox(ProfChatWin *chatwin, gboolean new_win, ProfMessage *message, gboolean logit)
|
||||
{
|
||||
#ifdef HAVE_LIBGPGME
|
||||
//_clean_incoming_message(message);
|
||||
chatwin_incoming_msg(chatwin, message, new_win);
|
||||
log_database_add_incoming(message);
|
||||
if (logit) {
|
||||
chat_log_pgp_msg_in(message);
|
||||
}
|
||||
chatwin->pgp_recv = TRUE;
|
||||
//p_gpg_free_decrypted(message->plain);
|
||||
message->plain = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
_sv_ev_incoming_otr(ProfChatWin *chatwin, gboolean new_win, ProfMessage *message)
|
||||
{
|
||||
@ -604,7 +620,9 @@ sv_ev_incoming_message(ProfMessage *message)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (message->encrypted) {
|
||||
if( message->enc == PROF_MSG_ENC_OX) {
|
||||
_sv_ev_incoming_ox(chatwin, new_win, message, TRUE);
|
||||
} else if (message->encrypted) {
|
||||
if (chatwin->is_otr) {
|
||||
win_println((ProfWin*)chatwin, THEME_DEFAULT, "-", "PGP encrypted message received whilst in OTR session.");
|
||||
} else {
|
||||
@ -638,7 +656,9 @@ sv_ev_incoming_carbon(ProfMessage *message)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (message->encrypted) {
|
||||
if (message->enc == PROF_MSG_ENC_OX) {
|
||||
_sv_ev_incoming_ox(chatwin, new_win, message, FALSE);
|
||||
} else if (message->encrypted) {
|
||||
_sv_ev_incoming_pgp(chatwin, new_win, message, FALSE);
|
||||
} else if (message->enc == PROF_MSG_ENC_OMEMO) {
|
||||
_sv_ev_incoming_omemo(chatwin, new_win, message, FALSE);
|
||||
|
339
src/pgp/gpg.c
339
src/pgp/gpg.c
@ -72,6 +72,9 @@ static char* _remove_header_footer(char *str, const char *const footer);
|
||||
static char* _add_header_footer(const char *const str, const char *const header, const char *const footer);
|
||||
static void _save_pubkeys(void);
|
||||
|
||||
static gpgme_key_t _ox_key_lookup(const char *const barejid, gboolean secret_only);
|
||||
static gboolean _ox_key_is_usable(gpgme_key_t key, const char *const barejid, gboolean secret);
|
||||
|
||||
void
|
||||
_p_gpg_free_pubkeyid(ProfPGPPubKeyId *pubkeyid)
|
||||
{
|
||||
@ -787,6 +790,219 @@ p_gpg_format_fp_str(char *fp)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Public keys with XMPP-URI.
|
||||
*
|
||||
* This function will look for all public key with a XMPP-URI as UID.
|
||||
*
|
||||
*/
|
||||
GHashTable* ox_gpg_public_keys(void){
|
||||
gpgme_error_t error;
|
||||
GHashTable *result = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_p_gpg_free_key);
|
||||
|
||||
gpgme_ctx_t ctx;
|
||||
error = gpgme_new(&ctx);
|
||||
|
||||
if (error) {
|
||||
log_error("OX - gpgme_new failed: %s %s", gpgme_strsource(error), gpgme_strerror(error));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
error = gpgme_op_keylist_start(ctx, NULL, 0); // all public keys
|
||||
if (error == GPG_ERR_NO_ERROR) {
|
||||
gpgme_key_t key;
|
||||
error = gpgme_op_keylist_next(ctx, &key);
|
||||
if ( error != GPG_ERR_EOF && error != GPG_ERR_NO_ERROR) {
|
||||
log_error("OX: gpgme_op_keylist_next %s %s", gpgme_strsource(error), gpgme_strerror(error));
|
||||
g_hash_table_destroy(result);
|
||||
return NULL;
|
||||
}
|
||||
while (!error) {
|
||||
// Looking for XMPP URI UID
|
||||
gpgme_user_id_t uid = key->uids;
|
||||
gpgme_user_id_t xmppid = NULL;
|
||||
while (!xmppid && uid) {
|
||||
if( uid->name && strlen(uid->name) >= 10 ) {
|
||||
if( strstr(uid->name, "xmpp:") == uid->name ) {
|
||||
xmppid = uid;
|
||||
}
|
||||
}
|
||||
uid = uid->next;
|
||||
}
|
||||
|
||||
if(xmppid) {
|
||||
// Build Key information about all subkey
|
||||
gpgme_subkey_t sub = key->subkeys;
|
||||
|
||||
ProfPGPKey *p_pgpkey = _p_gpg_key_new();
|
||||
p_pgpkey->id = strdup(sub->keyid);
|
||||
p_pgpkey->name = strdup(xmppid->uid);
|
||||
p_pgpkey->fp = strdup(sub->fpr);
|
||||
if (sub->can_encrypt) p_pgpkey->encrypt = TRUE;
|
||||
if (sub->can_authenticate) p_pgpkey->authenticate = TRUE;
|
||||
if (sub->can_certify) p_pgpkey->certify = TRUE;
|
||||
if (sub->can_sign) p_pgpkey->sign = TRUE;
|
||||
|
||||
sub = sub->next;
|
||||
while (sub) {
|
||||
if (sub->can_encrypt) p_pgpkey->encrypt = TRUE;
|
||||
if (sub->can_authenticate) p_pgpkey->authenticate = TRUE;
|
||||
if (sub->can_certify) p_pgpkey->certify = TRUE;
|
||||
if (sub->can_sign) p_pgpkey->sign = TRUE;
|
||||
|
||||
sub = sub->next;
|
||||
}
|
||||
|
||||
g_hash_table_insert(result, strdup(p_pgpkey->name), p_pgpkey);
|
||||
|
||||
}
|
||||
gpgme_key_unref(key);
|
||||
error = gpgme_op_keylist_next(ctx, &key);
|
||||
}
|
||||
}
|
||||
gpgme_release(ctx);
|
||||
|
||||
//autocomplete_clear(key_ac);
|
||||
// GList *ids = g_hash_table_get_keys(result);
|
||||
// GList *curr = ids;
|
||||
// while (curr) {
|
||||
// ProfPGPKey *key = g_hash_table_lookup(result, curr->data);
|
||||
// autocomplete_add(key_ac, key->id);
|
||||
// curr = curr->next;
|
||||
// }
|
||||
// g_list_free(ids);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
char* p_ox_gpg_signcrypt(const char* const sender_barejid, const char* const recipient_barejid , const char* const message) {
|
||||
setlocale (LC_ALL, "");
|
||||
gpgme_check_version (NULL);
|
||||
gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
|
||||
gpgme_ctx_t ctx;
|
||||
gpgme_error_t error = gpgme_new (&ctx);
|
||||
if(GPG_ERR_NO_ERROR != error ) {
|
||||
printf("gpgme_new: %d\n", error);
|
||||
return NULL;
|
||||
}
|
||||
error = gpgme_set_protocol(ctx, GPGME_PROTOCOL_OPENPGP);
|
||||
if(error != 0) {
|
||||
log_error("GpgME Error: %s", gpgme_strerror(error));
|
||||
}
|
||||
gpgme_set_armor(ctx,0);
|
||||
gpgme_set_textmode(ctx,0);
|
||||
gpgme_set_offline(ctx,1);
|
||||
gpgme_set_keylist_mode(ctx, GPGME_KEYLIST_MODE_LOCAL);
|
||||
if(error != 0) {
|
||||
log_error("GpgME Error: %s", gpgme_strerror(error));
|
||||
}
|
||||
|
||||
gpgme_key_t recp[3];
|
||||
recp[0] = NULL,
|
||||
recp[1] = NULL;
|
||||
|
||||
char* xmpp_jid_me = alloca( (strlen(sender_barejid)+6) * sizeof(char) );
|
||||
char* xmpp_jid_recipient = alloca( (strlen(recipient_barejid)+6) * sizeof(char) );
|
||||
|
||||
strcpy(xmpp_jid_me, "xmpp:");
|
||||
strcpy(xmpp_jid_recipient, "xmpp:");
|
||||
strcat(xmpp_jid_me, sender_barejid);
|
||||
strcat(xmpp_jid_recipient,recipient_barejid);
|
||||
|
||||
gpgme_signers_clear(ctx);
|
||||
|
||||
// lookup own key
|
||||
recp[0] = _ox_key_lookup(sender_barejid, TRUE);
|
||||
if(error != 0) {
|
||||
log_error("Key not found for %s. GpgME Error: %s", xmpp_jid_me, gpgme_strerror(error));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
error = gpgme_signers_add(ctx,recp[0]);
|
||||
if(error != 0) {
|
||||
log_error("gpgme_signers_add %s. GpgME Error: %s", xmpp_jid_me, gpgme_strerror(error));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// lookup key of recipient
|
||||
recp[1] = _ox_key_lookup(recipient_barejid, FALSE);
|
||||
if(error != 0) {
|
||||
log_error("Key not found for %s. GpgME Error: %s", xmpp_jid_recipient, gpgme_strerror(error));
|
||||
return NULL;
|
||||
}
|
||||
recp[2] = NULL;
|
||||
log_debug("%s <%s>", recp[0]->uids->name, recp[0]->uids->email);
|
||||
log_debug("%s <%s>", recp[1]->uids->name, recp[1]->uids->email);
|
||||
|
||||
gpgme_encrypt_flags_t flags = 0;
|
||||
|
||||
gpgme_data_t plain;
|
||||
gpgme_data_t cipher;
|
||||
|
||||
error = gpgme_data_new (&plain);
|
||||
if(error != 0) {
|
||||
log_error("GpgME Error: %s", gpgme_strerror(error));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
error = gpgme_data_new_from_mem(&plain, message, strlen(message),0);
|
||||
if(error != 0) {
|
||||
log_error("GpgME Error: %s", gpgme_strerror(error));
|
||||
return NULL;
|
||||
}
|
||||
error = gpgme_data_new (&cipher);
|
||||
if(error != 0) {
|
||||
log_error("GpgME Error: %s", gpgme_strerror(error));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
error = gpgme_op_encrypt_sign ( ctx, recp, flags, plain, cipher);
|
||||
if(error != 0) {
|
||||
log_error("GpgME Error: %s", gpgme_strerror(error));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t len;
|
||||
char *cipher_str = gpgme_data_release_and_get_mem(cipher, &len);
|
||||
char* result = g_base64_encode( (unsigned char*) cipher_str,len);
|
||||
gpgme_key_release (recp[0]);
|
||||
gpgme_key_release (recp[1]);
|
||||
gpgme_release (ctx);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
gboolean ox_is_private_key_available(const char *const barejid) {
|
||||
g_assert(barejid);
|
||||
gboolean result = FALSE;
|
||||
|
||||
gpgme_key_t key = _ox_key_lookup(barejid, TRUE);
|
||||
if(key) {
|
||||
if (_ox_key_is_usable(key, barejid, TRUE) ) {
|
||||
result = TRUE;
|
||||
}
|
||||
gpgme_key_unref(key);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
gboolean ox_is_public_key_available(const char *const barejid) {
|
||||
g_assert(barejid);
|
||||
gboolean result = FALSE;
|
||||
gpgme_key_t key = _ox_key_lookup(barejid, FALSE);
|
||||
if(key) {
|
||||
if (_ox_key_is_usable(key, barejid, FALSE) ) {
|
||||
result = TRUE;
|
||||
}
|
||||
gpgme_key_unref(key);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static char*
|
||||
_remove_header_footer(char *str, const char *const footer)
|
||||
{
|
||||
@ -837,3 +1053,126 @@ _save_pubkeys(void)
|
||||
g_chmod(pubsloc, S_IRUSR | S_IWUSR);
|
||||
g_free(g_pubkeys_data);
|
||||
}
|
||||
|
||||
static gpgme_key_t _ox_key_lookup(const char *const barejid, gboolean secret_only) {
|
||||
g_assert(barejid);
|
||||
log_debug("Looking for %s key: %s", secret_only == TRUE ? "Private" : "Public", barejid);
|
||||
gpgme_key_t key = NULL;
|
||||
gpgme_error_t error;
|
||||
|
||||
gpgme_ctx_t ctx;
|
||||
error = gpgme_new(&ctx);
|
||||
|
||||
if (error) {
|
||||
log_error("OX - gpgme_new failed: %s %s", gpgme_strsource(error), gpgme_strerror(error));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
error = gpgme_op_keylist_start(ctx, NULL, secret_only);
|
||||
if (error == GPG_ERR_NO_ERROR) {
|
||||
error = gpgme_op_keylist_next(ctx, &key);
|
||||
if ( error != GPG_ERR_EOF && error != GPG_ERR_NO_ERROR) {
|
||||
log_error("OX: gpgme_op_keylist_next %s %s", gpgme_strsource(error), gpgme_strerror(error));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GString* xmppuri = g_string_new("xmpp:");
|
||||
g_string_append(xmppuri,barejid);
|
||||
|
||||
while (!error) {
|
||||
// Looking for XMPP URI UID
|
||||
gpgme_user_id_t uid = key->uids;
|
||||
|
||||
while ( uid ) {
|
||||
if( uid->name && strlen(uid->name) >= 10 ) {
|
||||
if( g_strcmp0(uid->name, xmppuri->str) == 0 ) {
|
||||
gpgme_release(ctx);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
uid = uid->next;
|
||||
}
|
||||
gpgme_key_unref(key);
|
||||
error = gpgme_op_keylist_next(ctx, &key);
|
||||
}
|
||||
}
|
||||
gpgme_release(ctx);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static gboolean _ox_key_is_usable(gpgme_key_t key, const char *const barejid, gboolean secret) {
|
||||
gboolean result = TRUE;
|
||||
|
||||
if(key->revoked) result = FALSE;
|
||||
if(key->expired) result = FALSE;
|
||||
if(key->disabled) result = FALSE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief XMPP-OX: Decrypt OX Message.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param base64 base64_encode OpenPGP message.
|
||||
*
|
||||
* @result decrypt XMPP OX Message NULL terminated C-String
|
||||
*/
|
||||
char* p_ox_gpg_decrypt(char* base64) {
|
||||
setlocale (LC_ALL, "");
|
||||
gpgme_check_version (NULL);
|
||||
gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
|
||||
gpgme_ctx_t ctx;
|
||||
gpgme_error_t error = gpgme_new (&ctx);
|
||||
if(GPG_ERR_NO_ERROR != error ) {
|
||||
printf("gpgme_new: %d\n", error);
|
||||
return NULL;
|
||||
}
|
||||
error = gpgme_set_protocol(ctx, GPGME_PROTOCOL_OPENPGP);
|
||||
if(error != 0) {
|
||||
log_error("GpgME Error: %s", gpgme_strerror(error));
|
||||
}
|
||||
gpgme_set_armor(ctx,0);
|
||||
gpgme_set_textmode(ctx,0);
|
||||
gpgme_set_offline(ctx,1);
|
||||
gpgme_set_keylist_mode(ctx, GPGME_KEYLIST_MODE_LOCAL);
|
||||
if(error != 0) {
|
||||
log_error("GpgME Error: %s", gpgme_strerror(error));
|
||||
}
|
||||
|
||||
gpgme_data_t plain = NULL;
|
||||
gpgme_data_t cipher = NULL;
|
||||
|
||||
gsize s;
|
||||
guchar* encypted = g_base64_decode(base64, &s);
|
||||
error = gpgme_data_new_from_mem(&cipher, (char*)encypted, s,0);
|
||||
if(error != 0) {
|
||||
log_error("GpgME Error gpgme_data_new_from_mem: %s", gpgme_strerror(error));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
error = gpgme_data_new (&plain);
|
||||
if(error != 0) {
|
||||
log_error("GpgME Error: %s", gpgme_strerror(error));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
error = gpgme_op_decrypt_verify(ctx, cipher, plain);
|
||||
if(error != 0) {
|
||||
log_error("GpgME Error gpgme_op_decrypt: %s", gpgme_strerror(error));
|
||||
error = gpgme_op_decrypt(ctx, cipher, plain);
|
||||
if ( error != 0 ) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
size_t len;
|
||||
char *plain_str = gpgme_data_release_and_get_mem(plain, &len);
|
||||
char* result = malloc(len+1);
|
||||
strcpy(result, plain_str);
|
||||
result[len] = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -72,4 +72,20 @@ char* p_gpg_autocomplete_key(const char *const search_str, gboolean previous, vo
|
||||
void p_gpg_autocomplete_key_reset(void);
|
||||
char* p_gpg_format_fp_str(char *fp);
|
||||
|
||||
char* p_ox_gpg_signcrypt(const char* const sender_barejid, const char* const recipient_barejid , const char* const message);
|
||||
|
||||
char* p_ox_gpg_decrypt(char* base64);
|
||||
|
||||
/*!
|
||||
* \brief List of public keys with xmpp-URI.
|
||||
*
|
||||
* @returns GHashTable* with GString* xmpp-uri and ProfPGPKey* value. Empty
|
||||
* hash, if there is no key. NULL in case of error.
|
||||
*
|
||||
*/
|
||||
GHashTable* ox_gpg_public_keys(void);
|
||||
|
||||
gboolean ox_is_private_key_available(const char *const barejid);
|
||||
gboolean ox_is_public_key_available(const char *const barejid);
|
||||
|
||||
#endif
|
||||
|
@ -90,6 +90,9 @@ chatwin_new(const char *const barejid)
|
||||
if (prefs_get_boolean(PREF_MAM)) {
|
||||
iq_mam_request(chatwin);
|
||||
}
|
||||
// XEP-0373: OpenPGP for XMPP
|
||||
chatwin->is_ox = FALSE;
|
||||
|
||||
return chatwin;
|
||||
}
|
||||
|
||||
@ -344,6 +347,8 @@ chatwin_outgoing_msg(ProfChatWin *chatwin, const char *const message, char *id,
|
||||
enc_char = prefs_get_pgp_char();
|
||||
} else if (enc_mode == PROF_MSG_ENC_OMEMO) {
|
||||
enc_char = prefs_get_omemo_char();
|
||||
} else if (enc_mode == PROF_MSG_ENC_OX) {
|
||||
enc_char = prefs_get_ox_char();
|
||||
} else {
|
||||
enc_char = strdup("-");
|
||||
}
|
||||
|
@ -503,6 +503,7 @@ mucwin_outgoing_msg(ProfMucWin *mucwin, const char *const message, const char *c
|
||||
ProfWin *window = (ProfWin*)mucwin;
|
||||
char *mynick = muc_nick(mucwin->roomjid);
|
||||
|
||||
// displayed message char
|
||||
char *ch;
|
||||
if (mucwin->message_char) {
|
||||
ch = strdup(mucwin->message_char);
|
||||
@ -512,6 +513,8 @@ mucwin_outgoing_msg(ProfMucWin *mucwin, const char *const message, const char *c
|
||||
ch = prefs_get_pgp_char();
|
||||
} else if (enc_mode == PROF_MSG_ENC_OMEMO) {
|
||||
ch = prefs_get_omemo_char();
|
||||
} else if (enc_mode == PROF_MSG_ENC_OX) {
|
||||
ch = prefs_get_omemo_char();
|
||||
} else {
|
||||
ch = strdup("-");
|
||||
}
|
||||
|
@ -439,6 +439,20 @@ _show_privacy(ProfChatWin *chatwin)
|
||||
return;
|
||||
}
|
||||
|
||||
// XEP-0373: OpenPGP for XMPP
|
||||
if (chatwin->is_ox) {
|
||||
wprintw(win, " ");
|
||||
wattron(win, bracket_attrs);
|
||||
wprintw(win, "[");
|
||||
wattroff(win, bracket_attrs);
|
||||
wattron(win, encrypted_attrs);
|
||||
wprintw(win, "OX");
|
||||
wattroff(win, encrypted_attrs);
|
||||
wattron(win, bracket_attrs);
|
||||
wprintw(win, "]");
|
||||
wattroff(win, bracket_attrs);
|
||||
}
|
||||
|
||||
if (chatwin->is_otr) {
|
||||
wprintw(win, " ");
|
||||
wattron(win, bracket_attrs);
|
||||
|
@ -155,6 +155,7 @@ typedef struct prof_chat_win_t {
|
||||
gboolean pgp_send;
|
||||
gboolean pgp_recv;
|
||||
gboolean is_omemo;
|
||||
gboolean is_ox; // XEP-0373: OpenPGP for XMPP
|
||||
char *resource_override;
|
||||
gboolean history_shown;
|
||||
unsigned long memcheck;
|
||||
|
@ -1144,6 +1144,8 @@ win_print_incoming(ProfWin *window, const char *const display_name_from, ProfMes
|
||||
enc_char = prefs_get_otr_char();
|
||||
} else if (message->enc == PROF_MSG_ENC_PGP) {
|
||||
enc_char = prefs_get_pgp_char();
|
||||
} else if (message->enc == PROF_MSG_ENC_OX) { // XEP-0373: OpenPGP for XMPP
|
||||
enc_char = prefs_get_ox_char();
|
||||
} else if (message->enc == PROF_MSG_ENC_OMEMO) {
|
||||
enc_char = prefs_get_omemo_char();
|
||||
} else {
|
||||
|
@ -85,10 +85,13 @@ static void _handle_conference(xmpp_stanza_t *const stanza);
|
||||
static void _handle_captcha(xmpp_stanza_t *const stanza);
|
||||
static void _handle_receipt_received(xmpp_stanza_t *const stanza);
|
||||
static void _handle_chat(xmpp_stanza_t *const stanza, gboolean is_mam);
|
||||
static void _handle_ox_chat(xmpp_stanza_t *const stanza, ProfMessage *message, gboolean is_mam);
|
||||
static gboolean _handle_mam(xmpp_stanza_t *const stanza);
|
||||
|
||||
static void _send_message_stanza(xmpp_stanza_t *const stanza);
|
||||
|
||||
static xmpp_stanza_t* _openpgp_signcrypt(xmpp_ctx_t* ctx, const char* const to, const char* const text);
|
||||
|
||||
static GHashTable *pubsub_event_handlers;
|
||||
|
||||
static int
|
||||
@ -353,6 +356,7 @@ message_send_chat_pgp(const char *const barejid, const char *const msg, gboolean
|
||||
}
|
||||
account_free(account);
|
||||
#else
|
||||
// ?
|
||||
message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id);
|
||||
xmpp_message_set_body(message, msg);
|
||||
#endif
|
||||
@ -376,6 +380,70 @@ message_send_chat_pgp(const char *const barejid, const char *const msg, gboolean
|
||||
return id;
|
||||
}
|
||||
|
||||
// XEP-0373: OpenPGP for XMPP
|
||||
|
||||
char*
|
||||
message_send_chat_ox(const char *const barejid, const char *const msg, gboolean request_receipt, const char *const replace_id)
|
||||
{
|
||||
xmpp_ctx_t * const ctx = connection_get_ctx();
|
||||
|
||||
char *state = chat_session_get_state(barejid);
|
||||
char *jid = chat_session_get_jid(barejid);
|
||||
char *id = connection_create_stanza_id();
|
||||
|
||||
xmpp_stanza_t *message = NULL;
|
||||
Jid *jidp = jid_create(jid);
|
||||
|
||||
char *account_name = session_get_account_name();
|
||||
ProfAccount *account = accounts_get_account(account_name);
|
||||
|
||||
message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id);
|
||||
xmpp_message_set_body(message, "This message is encrypted (XEP-0373: OpenPGP for XMPP).");
|
||||
|
||||
xmpp_stanza_t *openpgp = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(openpgp, STANZA_NAME_OPENPGP);
|
||||
xmpp_stanza_set_ns(openpgp, STANZA_NS_OPENPGP_0);
|
||||
|
||||
xmpp_stanza_t * signcrypt = _openpgp_signcrypt(ctx, barejid, msg);
|
||||
char* c;
|
||||
size_t s;
|
||||
xmpp_stanza_to_text(signcrypt, &c,&s);
|
||||
char* signcrypt_e = p_ox_gpg_signcrypt(account->jid, barejid, c);
|
||||
if( signcrypt_e == NULL ) {
|
||||
log_error("Message not signcrypted.");
|
||||
return NULL;
|
||||
}
|
||||
// BASE64_OPENPGP_MESSAGE
|
||||
xmpp_stanza_t* base64_openpgp_message = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_text(base64_openpgp_message,signcrypt_e);
|
||||
xmpp_stanza_add_child(openpgp, base64_openpgp_message);
|
||||
xmpp_stanza_add_child(message, openpgp);
|
||||
|
||||
xmpp_stanza_to_text(message, &c,&s);
|
||||
|
||||
account_free(account);
|
||||
jid_destroy(jidp);
|
||||
free(jid);
|
||||
|
||||
if (state) {
|
||||
stanza_attach_state(ctx, message, state);
|
||||
}
|
||||
|
||||
if (request_receipt) {
|
||||
stanza_attach_receipt_request(ctx, message);
|
||||
}
|
||||
|
||||
if (replace_id) {
|
||||
stanza_attach_correction(ctx, message, replace_id);
|
||||
}
|
||||
|
||||
_send_message_stanza(message);
|
||||
xmpp_stanza_release(message);
|
||||
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
char*
|
||||
message_send_chat_otr(const char *const barejid, const char *const msg, gboolean request_receipt, const char *const replace_id)
|
||||
{
|
||||
@ -1140,6 +1208,12 @@ _handle_carbons(xmpp_stanza_t *const stanza)
|
||||
if (x) {
|
||||
message->encrypted = xmpp_stanza_get_text(x);
|
||||
}
|
||||
// OX
|
||||
xmpp_stanza_t *ox = xmpp_stanza_get_child_by_ns(message_stanza, STANZA_NS_OPENPGP_0);
|
||||
if( ox ) {
|
||||
message->enc=PROF_MSG_ENC_OX;
|
||||
_handle_ox_chat(message_stanza,message, FALSE);
|
||||
}
|
||||
|
||||
//TODO: maybe also add is_carbon maybe even an enum with outgoing/incoming
|
||||
//could be that then we can have sv_ev_carbon no incoming/outgoing
|
||||
@ -1260,6 +1334,12 @@ _handle_chat(xmpp_stanza_t *const stanza, gboolean is_mam)
|
||||
message->encrypted = xmpp_stanza_get_text(encrypted);
|
||||
}
|
||||
|
||||
xmpp_stanza_t *ox = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_OPENPGP_0);
|
||||
if( ox ) {
|
||||
message->enc=PROF_MSG_ENC_OX;
|
||||
_handle_ox_chat(stanza,message, FALSE);
|
||||
}
|
||||
|
||||
if (message->plain || message->body || message->encrypted) {
|
||||
sv_ev_incoming_message(message);
|
||||
|
||||
@ -1290,6 +1370,35 @@ _handle_chat(xmpp_stanza_t *const stanza, gboolean is_mam)
|
||||
message_free(message);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Handle incoming XMMP-OX chat message.
|
||||
*
|
||||
*
|
||||
*/
|
||||
static void _handle_ox_chat(xmpp_stanza_t *const stanza, ProfMessage *message, gboolean is_mam) {
|
||||
xmpp_stanza_t *ox = stanza_get_child_by_name_and_ns(stanza, "openpgp", STANZA_NS_OPENPGP_0);
|
||||
message->plain = p_ox_gpg_decrypt(xmpp_stanza_get_text(ox));
|
||||
|
||||
// Implementation for libstrophe 0.10.
|
||||
/*
|
||||
xmpp_stanza_t *x = xmpp_stanza_new_from_string(connection_get_ctx(), message->plain);
|
||||
xmpp_stanza_t *p = xmpp_stanza_get_child_by_name(x, "payload");
|
||||
xmpp_stanza_t *b = xmpp_stanza_get_child_by_name(p, "body");
|
||||
message->plain = xmpp_stanza_get_text(b);
|
||||
if(message->plain == NULL ) {
|
||||
message->plain = xmpp_stanza_get_text(stanza);
|
||||
}
|
||||
message->encrypted = xmpp_stanza_get_text(ox);
|
||||
*/
|
||||
|
||||
if(message->plain == NULL ) {
|
||||
message->plain = xmpp_stanza_get_text(stanza);
|
||||
}
|
||||
message->encrypted = xmpp_stanza_get_text(ox);
|
||||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_handle_mam(xmpp_stanza_t *const stanza)
|
||||
{
|
||||
@ -1372,3 +1481,64 @@ message_is_sent_by_us(const ProfMessage *const message, bool checkOID) {
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
xmpp_stanza_t* _openpgp_signcrypt(xmpp_ctx_t* ctx, const char* const to, const char* const text) {
|
||||
|
||||
time_t now = time(NULL);
|
||||
struct tm* tm = localtime(&now);
|
||||
char buf[255];
|
||||
strftime(buf, sizeof(buf), "%FT%T%z", tm);
|
||||
int randnr = rand() % 5;
|
||||
char rpad_data[randnr];
|
||||
for(int i = 0; i < randnr-1; i++) {
|
||||
rpad_data[i] = 'c';
|
||||
}
|
||||
rpad_data[randnr-1] = '\0';
|
||||
|
||||
// signcrypt
|
||||
xmpp_stanza_t *signcrypt = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(signcrypt, "signcrypt");
|
||||
xmpp_stanza_set_ns(signcrypt, "urn:xmpp:openpgp:0");
|
||||
// to
|
||||
xmpp_stanza_t *s_to = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(s_to, "to");
|
||||
xmpp_stanza_set_attribute(s_to, "jid", to);
|
||||
// time
|
||||
xmpp_stanza_t *time = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(time, "time");
|
||||
xmpp_stanza_set_attribute(time, "stamp", buf);
|
||||
xmpp_stanza_set_name(time, "time");
|
||||
// rpad
|
||||
xmpp_stanza_t *rpad = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(rpad, "rpad");
|
||||
xmpp_stanza_t *rpad_text = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_text(rpad_text, rpad_data);
|
||||
// payload
|
||||
xmpp_stanza_t *payload= xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(payload, "payload");
|
||||
// body
|
||||
xmpp_stanza_t *body = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(body, "body");
|
||||
xmpp_stanza_set_ns(body, "jabber:client");
|
||||
// text
|
||||
xmpp_stanza_t *body_text = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_text(body_text, text);
|
||||
xmpp_stanza_add_child(signcrypt,s_to);
|
||||
xmpp_stanza_add_child(signcrypt,time);
|
||||
xmpp_stanza_add_child(signcrypt,rpad);
|
||||
xmpp_stanza_add_child(rpad,rpad_text);
|
||||
xmpp_stanza_add_child(signcrypt,payload);
|
||||
xmpp_stanza_add_child(payload, body);
|
||||
xmpp_stanza_add_child(body, body_text);
|
||||
|
||||
xmpp_stanza_release(body_text);
|
||||
xmpp_stanza_release(body);
|
||||
xmpp_stanza_release(rpad_text);
|
||||
xmpp_stanza_release(rpad);
|
||||
xmpp_stanza_release(time);
|
||||
xmpp_stanza_release(s_to);
|
||||
|
||||
return signcrypt;
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,8 @@
|
||||
#define STANZA_NAME_PRESENCE "presence"
|
||||
#define STANZA_NAME_PRIORITY "priority"
|
||||
#define STANZA_NAME_X "x"
|
||||
// XEP-0373: OpenPGP for XMPP
|
||||
#define STANZA_NAME_OPENPGP "openpgp"
|
||||
#define STANZA_NAME_SHOW "show"
|
||||
#define STANZA_NAME_STATUS "status"
|
||||
#define STANZA_NAME_IQ "iq"
|
||||
@ -192,6 +194,8 @@
|
||||
#define STANZA_NS_RECEIPTS "urn:xmpp:receipts"
|
||||
#define STANZA_NS_SIGNED "jabber:x:signed"
|
||||
#define STANZA_NS_ENCRYPTED "jabber:x:encrypted"
|
||||
// XEP-0373: OpenPGP for XMPP
|
||||
#define STANZA_NS_OPENPGP_0 "urn:xmpp:openpgp:0"
|
||||
#define STANZA_NS_HTTP_UPLOAD "urn:xmpp:http:upload"
|
||||
#define STANZA_NS_X_OOB "jabber:x:oob"
|
||||
#define STANZA_NS_BLOCKING "urn:xmpp:blocking"
|
||||
|
@ -126,7 +126,8 @@ typedef enum {
|
||||
PROF_MSG_ENC_NONE,
|
||||
PROF_MSG_ENC_OTR,
|
||||
PROF_MSG_ENC_PGP,
|
||||
PROF_MSG_ENC_OMEMO
|
||||
PROF_MSG_ENC_OMEMO,
|
||||
PROF_MSG_ENC_OX
|
||||
} prof_enc_t;
|
||||
|
||||
typedef enum {
|
||||
@ -192,6 +193,8 @@ const char* connection_get_profanity_identifier(void);
|
||||
char* message_send_chat(const char *const barejid, const char *const msg, const char *const oob_url, gboolean request_receipt, const char *const replace_id);
|
||||
char* message_send_chat_otr(const char *const barejid, const char *const msg, gboolean request_receipt, const char *const replace_id);
|
||||
char* message_send_chat_pgp(const char *const barejid, const char *const msg, gboolean request_receipt, const char *const replace_id);
|
||||
// XEP-0373: OpenPGP for XMPP
|
||||
char* message_send_chat_ox(const char *const barejid, const char *const msg, gboolean request_receipt, const char *const replace_id);
|
||||
char* message_send_chat_omemo(const char *const jid, uint32_t sid, GList *keys, const unsigned char *const iv, size_t iv_len, const unsigned char *const ciphertext, size_t ciphertext_len, gboolean request_receipt, gboolean muc, const char *const replace_id);
|
||||
char* message_send_private(const char *const fulljid, const char *const msg, const char *const oob_url);
|
||||
char* message_send_groupchat(const char *const roomjid, const char *const msg, const char *const oob_url, const char *const replace_id);
|
||||
|
Loading…
Reference in New Issue
Block a user