Compare commits
11 Commits
build/reen
...
3fa96eec18
| Author | SHA1 | Date | |
|---|---|---|---|
|
3fa96eec18
|
|||
|
f66d21e1c1
|
|||
|
8ed922f827
|
|||
|
ea8a758ecf
|
|||
|
2808def933
|
|||
|
741dc4c275
|
|||
|
65cf9ddb9c
|
|||
|
51d2355d97
|
|||
|
e33c7a477d
|
|||
|
f4405d114a
|
|||
|
442bfb6ce1
|
@@ -5,6 +5,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
autoconf \
|
||||
autoconf-archive \
|
||||
automake \
|
||||
ca-certificates \
|
||||
expect \
|
||||
gcc \
|
||||
git \
|
||||
@@ -36,7 +37,7 @@ RUN mkdir -p /usr/src/{stabber,libstrophe,profanity}
|
||||
WORKDIR /usr/src
|
||||
|
||||
#RUN git clone https://github.com/boothj5/stabber
|
||||
RUN git clone -c http.sslverify=false https://github.com/strophe/libstrophe
|
||||
RUN git clone --depth 1 https://git.jabber.space/devs/libstrophe-gh.git
|
||||
|
||||
#WORKDIR /usr/src/stabber
|
||||
#RUN ./bootstrap.sh
|
||||
@@ -47,7 +48,7 @@ RUN git clone -c http.sslverify=false https://github.com/strophe/libstrophe
|
||||
WORKDIR /usr/src/libstrophe
|
||||
RUN ./bootstrap.sh
|
||||
RUN ./configure --prefix=/usr
|
||||
RUN make
|
||||
RUN make -j$(nproc)
|
||||
RUN make install
|
||||
|
||||
WORKDIR /usr/src/profanity
|
||||
|
||||
@@ -9,6 +9,7 @@ RUN dnf install -y \
|
||||
autoconf-archive \
|
||||
automake \
|
||||
awk \
|
||||
ca-certificates \
|
||||
expect-devel \
|
||||
gcc \
|
||||
git \
|
||||
@@ -56,11 +57,11 @@ WORKDIR /usr/src
|
||||
|
||||
WORKDIR /usr/src
|
||||
RUN mkdir -p /usr/src/libstrophe
|
||||
RUN git clone -c http.sslverify=false https://github.com/strophe/libstrophe
|
||||
RUN git clone --depth 1 https://git.jabber.space/devs/libstrophe-gh.git
|
||||
WORKDIR /usr/src/libstrophe
|
||||
RUN ./bootstrap.sh
|
||||
RUN ./configure --prefix=/usr
|
||||
RUN make
|
||||
RUN make -j$(nproc)
|
||||
RUN make install
|
||||
|
||||
RUN mkdir -p /usr/src/profanity
|
||||
|
||||
@@ -6,6 +6,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
autoconf \
|
||||
autoconf-archive \
|
||||
automake \
|
||||
ca-certificates \
|
||||
expect \
|
||||
gcc \
|
||||
git \
|
||||
@@ -37,7 +38,7 @@ RUN mkdir -p /usr/src/{stabber,libstrophe,profanity}
|
||||
WORKDIR /usr/src
|
||||
|
||||
#RUN git clone https://github.com/boothj5/stabber
|
||||
RUN git clone -c http.sslverify=false https://github.com/strophe/libstrophe
|
||||
RUN git clone --depth 1 https://git.jabber.space/devs/libstrophe-gh.git
|
||||
|
||||
# TODO: Re-enable once libmicrohttpd-dev has been updated.
|
||||
#WORKDIR /usr/src/stabber
|
||||
@@ -49,7 +50,7 @@ RUN git clone -c http.sslverify=false https://github.com/strophe/libstrophe
|
||||
WORKDIR /usr/src/libstrophe
|
||||
RUN ./bootstrap.sh
|
||||
RUN ./configure --prefix=/usr
|
||||
RUN make
|
||||
RUN make -j$(nproc)
|
||||
RUN make install
|
||||
|
||||
WORKDIR /usr/src/profanity
|
||||
|
||||
@@ -166,6 +166,7 @@ unittest_sources = \
|
||||
tests/unittests/test_cmd_disconnect.c tests/unittests/test_cmd_disconnect.h \
|
||||
tests/unittests/test_callbacks.c tests/unittests/test_callbacks.h \
|
||||
tests/unittests/test_plugins_disco.c tests/unittests/test_plugins_disco.h \
|
||||
tests/unittests/test_forced_encryption.c tests/unittests/test_forced_encryption.h \
|
||||
tests/unittests/unittests.c
|
||||
|
||||
functionaltest_sources = \
|
||||
|
||||
40
README.md
40
README.md
@@ -1,40 +1,36 @@
|
||||
# Profanity
|
||||
 [](https://github.com/profanity-im/profanity/graphs/contributors/) [](https://repology.org/project/profanity/versions)
|
||||
# CProof
|
||||

|
||||
|
||||
Profanity is a console based XMPP client inspired by [Irssi](http://www.irssi.org/).
|
||||
CProof is a console based XMPP chat client based on [Profanity](https://profanity-im.github.io/).
|
||||
|
||||

|
||||

|
||||
|
||||
See the [User Guide](https://profanity-im.github.io/userguide.html) for information on installing and using Profanity.
|
||||
See the [Quick Start Guide](https://jabber.space/getting-started/quick-start/) for information on installing and using CProof.
|
||||
|
||||
## Project
|
||||
This project is about freedom, privacy and choice. We want to enable people to chat with one another in a safe way. Thus supporting encryption (OTR, PGP, OMEMO, OX) and being decentralized, meaning everyone can run their own server. We believe [XMPP](https://xmpp.org/) is a great proven protocol with an excellent community serving this purpose well.
|
||||
|
||||
CProof enables you to communicate with privacy, freedom and comfort. Our open-source chat application delivers secure, end-to-end encrypted messaging (OTR, PGP, OMEMO, OX) built on the trusted [XMPP](https://xmpp.org/) protocol. With a decentralized design, you can connect directly or even host your own server, keeping your data in your hands. Whether you're chatting with friends or collaborating securely, CProof makes private communication simple, reliable, and truly yours.
|
||||
|
||||
## Installation
|
||||
Our [user guide](https://profanity-im.github.io/userguide.html) contains an [install](https://profanity-im.github.io/guide/latest/install.html) section and a section for [building](https://profanity-im.github.io/guide/latest/build.html) from source yourself.
|
||||
Check our [installation guide](https://jabber.space/getting-started/installation/) for detailed instructions.
|
||||
|
||||
## How to contribute
|
||||
We tried to sum things up on our [helpout](https://profanity-im.github.io/helpout.html) page.
|
||||
Additionally you can check out our [blog](https://profanity-im.github.io/blog/) where we have articles like:
|
||||
[How to get a backtrace](https://profanity-im.github.io/blog/post/how-to-get-a-backtrace/) and [Contributing a Patch via GitHub](https://profanity-im.github.io/blog/post/contributing-a-patch-via-github/).
|
||||
For more technical details check out our [CONTRIBUTING.md](CONTRIBUTING.md) file.
|
||||
See our [Helping Out](https://jabber.space/contributing/helpout/) page for a concise summary of ways to help us.
|
||||
|
||||
Review the [Contributing Guide](CONTRIBUTING.md) and [Code Overview](https://jabber.space/contributing/code-overview/) pages for advanced technical details.
|
||||
|
||||
## Getting help
|
||||
To get help, first read our [User Guide](https://profanity-im.github.io/userguide.html) then check out the [FAQ](https://profanity-im.github.io/faq.html).
|
||||
If you are having a problem then first search the [issue tracker](https://github.com/profanity-im/profanity/issues).
|
||||
If you don't find anything there either come to our [MUC](xmpp:profanity@rooms.dismail.de?join) or create a new issue depending on what your problem is.
|
||||
Prior to asking questions, check our [User Guide](https://profanity-im.github.io/userguide.html), then check out the [FAQ](https://jabber.space/about/faq/).
|
||||
|
||||
If you are still having a problem then search the [issue tracker](https://git.jabber.space/devs/cproof/issues).
|
||||
|
||||
As a last resort, feel free to write us on [support@jabber.tech](mailto:support@jabber.tech) or create a new issue depending on what your problem is.
|
||||
|
||||
## Links
|
||||
|
||||
### Website
|
||||
<!-- TODO:
|
||||
URL: https://jabber.space/
|
||||
-->
|
||||
Feel free to visit our website: [jabber.space](https://jabber.space/).
|
||||
|
||||
Repo: https://git.jabber.space/devs/profanity
|
||||
|
||||
<!-- TODO: blog/docs link -->
|
||||
You may also check the repository if you like, available on [git.jabber.space/devs/profanity](https://git.jabber.space/devs/profanity).
|
||||
|
||||
### Plugins
|
||||
Plugins repository: https://github.com/profanity-im/profanity-plugins
|
||||
Plugins repository: https://git.jabber.space/devs/cproof-plugins
|
||||
|
||||
@@ -144,7 +144,7 @@ do
|
||||
echo
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
./configure $features $*
|
||||
./configure -C $features $*
|
||||
|
||||
$MAKE CC="${CC}"
|
||||
$MAKE check
|
||||
|
||||
@@ -136,6 +136,7 @@ static char* _mood_autocomplete(ProfWin* window, const char* const input, gboole
|
||||
static char* _strophe_autocomplete(ProfWin* window, const char* const input, gboolean previous);
|
||||
static char* _adhoc_cmd_autocomplete(ProfWin* window, const char* const input, gboolean previous);
|
||||
static char* _vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous);
|
||||
static char* _force_encryption_autocomplete(ProfWin* window, const char* const input, gboolean previous);
|
||||
|
||||
static char* _script_autocomplete_func(const char* const prefix, gboolean previous, void* context);
|
||||
|
||||
@@ -296,6 +297,8 @@ static Autocomplete vcard_name_ac;
|
||||
static Autocomplete vcard_set_param_ac;
|
||||
static Autocomplete vcard_togglable_param_ac;
|
||||
static Autocomplete vcard_address_type_ac;
|
||||
static Autocomplete force_encryption_ac;
|
||||
static Autocomplete force_encryption_policy_ac;
|
||||
|
||||
static Autocomplete* all_acs[] = {
|
||||
&commands_ac,
|
||||
@@ -448,6 +451,8 @@ static Autocomplete* all_acs[] = {
|
||||
&vcard_set_param_ac,
|
||||
&vcard_togglable_param_ac,
|
||||
&vcard_address_type_ac,
|
||||
&force_encryption_ac,
|
||||
&force_encryption_policy_ac
|
||||
};
|
||||
|
||||
static GHashTable* ac_funcs = NULL;
|
||||
@@ -1343,6 +1348,13 @@ cmd_ac_init(void)
|
||||
autocomplete_add(vcard_address_type_ac, "domestic");
|
||||
autocomplete_add(vcard_address_type_ac, "international");
|
||||
|
||||
autocomplete_add(force_encryption_ac, "on");
|
||||
autocomplete_add(force_encryption_ac, "off");
|
||||
autocomplete_add(force_encryption_ac, "policy");
|
||||
|
||||
autocomplete_add(force_encryption_policy_ac, "block");
|
||||
autocomplete_add(force_encryption_policy_ac, "resend-to-confirm");
|
||||
|
||||
if (ac_funcs != NULL)
|
||||
g_hash_table_destroy(ac_funcs);
|
||||
ac_funcs = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
@@ -1415,6 +1427,7 @@ cmd_ac_init(void)
|
||||
g_hash_table_insert(ac_funcs, "/win", _win_autocomplete);
|
||||
g_hash_table_insert(ac_funcs, "/wins", _wins_autocomplete);
|
||||
g_hash_table_insert(ac_funcs, "/wintitle", _wintitle_autocomplete);
|
||||
g_hash_table_insert(ac_funcs, "/force-encryption", _force_encryption_autocomplete);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -4406,3 +4419,17 @@ _vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static char*
|
||||
_force_encryption_autocomplete(ProfWin* window, const char* const input, gboolean previous)
|
||||
{
|
||||
char* result = NULL;
|
||||
|
||||
result = autocomplete_param_with_ac(input, "/force-encryption policy", force_encryption_policy_ac, TRUE, previous);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = autocomplete_param_with_ac(input, "/force-encryption", force_encryption_ac, TRUE, previous);
|
||||
return result;
|
||||
}
|
||||
@@ -2729,6 +2729,7 @@ static const struct cmd_t command_defs[] = {
|
||||
{ "os on|off", "Choose whether to include the OS name if a user asks for software information (XEP-0092)." }
|
||||
)
|
||||
CMD_EXAMPLES(
|
||||
"/privacy",
|
||||
"/privacy logging off",
|
||||
"/privacy os off")
|
||||
},
|
||||
@@ -2744,6 +2745,31 @@ static const struct cmd_t command_defs[] = {
|
||||
"Redraw user interface. Can be used when some other program interrupted profanity or wrote to the same terminal and the interface looks \"broken\"." )
|
||||
},
|
||||
|
||||
{ CMD_PREAMBLE("/force-encryption",
|
||||
parse_args, 1, 3, &cons_encryption_setting)
|
||||
CMD_MAINFUNC(cmd_force_encryption)
|
||||
CMD_TAGS(
|
||||
CMD_TAG_CHAT)
|
||||
CMD_SYN(
|
||||
"/force-encryption",
|
||||
"/force-encryption on|off",
|
||||
"/force-encryption policy resend-to-confirm|block")
|
||||
CMD_DESC(
|
||||
"Configure forced encryption for outgoing messages in CProof. "
|
||||
"When enabled, restricts sending unencrypted messages based on the specified policy. "
|
||||
"Run without arguments to display current settings.")
|
||||
CMD_ARGS(
|
||||
{ "on|off", "Enable or disable forced encryption. When enabled, restricts unencrypted messages per the policy. When disabled, allows sending unencrypted messages without restrictions." },
|
||||
{ "policy resend-to-confirm|block", "Set the policy for unencrypted messages when forced encryption is enabled. 'resend-to-confirm' requires pressing Enter again to confirm sending an unencrypted message (default). 'block' prevents sending unencrypted messages entirely." }
|
||||
)
|
||||
CMD_EXAMPLES(
|
||||
"/force-encryption",
|
||||
"/force-encryption on",
|
||||
"/force-encryption off",
|
||||
"/force-encryption policy resend-to-confirm",
|
||||
"/force-encryption policy block")
|
||||
},
|
||||
|
||||
// NEXT-COMMAND (search helper)
|
||||
};
|
||||
|
||||
|
||||
@@ -1263,6 +1263,11 @@ cmd_sub(ProfWin* window, const char* const command, gchar** args)
|
||||
|
||||
auto_jid Jid* jidp = jid_create(jid);
|
||||
|
||||
if (jidp == NULL) {
|
||||
cons_show("Malformed JID: %s", jid);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (strcmp(subcmd, "allow") == 0) {
|
||||
presence_subscription(jidp->barejid, PRESENCE_SUBSCRIBED);
|
||||
cons_show("Accepted subscription for %s", jidp->barejid);
|
||||
@@ -3418,7 +3423,7 @@ cmd_caps(ProfWin* window, const char* const command, gchar** args)
|
||||
if (args[0]) {
|
||||
auto_jid Jid* jid = jid_create(args[0]);
|
||||
|
||||
if (jid->fulljid == NULL) {
|
||||
if (jid == NULL || jid->fulljid == NULL) {
|
||||
cons_show("You must provide a full jid to the /caps command.");
|
||||
} else {
|
||||
PContact pcontact = roster_get_contact(jid->barejid);
|
||||
@@ -10633,3 +10638,22 @@ cmd_vcard_save(ProfWin* window, const char* const command, gchar** args)
|
||||
cons_show("User vCard uploaded");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
cmd_force_encryption(ProfWin* window, const char* const command, gchar** args)
|
||||
{
|
||||
if (g_strv_length(args) == 1 && (g_strcmp0(args[0], "on") == 0 || g_strcmp0(args[0], "off") == 0)) {
|
||||
_cmd_set_boolean_preference(args[0], "Forces encryption", PREF_FORCE_ENCRYPTION);
|
||||
} else if (g_strv_length(args) == 2 && g_strcmp0(args[0], "policy") == 0) {
|
||||
if (g_strcmp0(args[1], "resend-to-confirm") != 0 && g_strcmp0(args[1], "block") != 0) {
|
||||
cons_show_error("Invalid policy: \"%s\". See '/help force-encryption' for details.", args[1]);
|
||||
return TRUE;
|
||||
}
|
||||
prefs_set_string(PREF_FORCE_ENCRYPTION_MODE, args[1]);
|
||||
cons_show("Force encryption policy has been set to \"%s\".", args[1]);
|
||||
} else {
|
||||
cons_bad_cmd_usage(command);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -269,5 +269,6 @@ gboolean cmd_vcard_photo(ProfWin* window, const char* const command, gchar** arg
|
||||
gboolean cmd_vcard_refresh(ProfWin* window, const char* const command, gchar** args);
|
||||
gboolean cmd_vcard_set(ProfWin* window, const char* const command, gchar** args);
|
||||
gboolean cmd_vcard_save(ProfWin* window, const char* const command, gchar** args);
|
||||
gboolean cmd_force_encryption(ProfWin* window, const char* const command, gchar** args);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1792,6 +1792,8 @@ _get_group(preference_t pref)
|
||||
case PREF_OUTGOING_STAMP:
|
||||
case PREF_INCOMING_STAMP:
|
||||
case PREF_MOOD:
|
||||
case PREF_FORCE_ENCRYPTION:
|
||||
case PREF_FORCE_ENCRYPTION_MODE:
|
||||
return PREF_GROUP_UI;
|
||||
case PREF_STATES:
|
||||
case PREF_OUTTYPE:
|
||||
@@ -2150,6 +2152,10 @@ _get_key(preference_t pref)
|
||||
return "strophe.sm.enabled";
|
||||
case PREF_STROPHE_SM_RESEND:
|
||||
return "strophe.sm.resend";
|
||||
case PREF_FORCE_ENCRYPTION:
|
||||
return "force-encryption.enabled";
|
||||
case PREF_FORCE_ENCRYPTION_MODE:
|
||||
return "force-encryption.policy";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@@ -2204,6 +2210,7 @@ _get_default_boolean(preference_t pref)
|
||||
case PREF_STROPHE_SM_RESEND:
|
||||
return TRUE;
|
||||
case PREF_PGP_PUBKEY_AUTOIMPORT:
|
||||
case PREF_FORCE_ENCRYPTION:
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
@@ -2310,6 +2317,8 @@ _get_default_string(preference_t pref)
|
||||
return "0";
|
||||
case PREF_DBLOG:
|
||||
return "on";
|
||||
case PREF_FORCE_ENCRYPTION_MODE:
|
||||
return "resend-to-confirm";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -187,6 +187,8 @@ typedef enum {
|
||||
PREF_STROPHE_SM_RESEND,
|
||||
PREF_VCARD_PHOTO_CMD,
|
||||
PREF_STATUSBAR_TABMODE,
|
||||
PREF_FORCE_ENCRYPTION,
|
||||
PREF_FORCE_ENCRYPTION_MODE
|
||||
} preference_t;
|
||||
|
||||
typedef struct prof_alias_t
|
||||
|
||||
@@ -42,9 +42,11 @@
|
||||
#include "log.h"
|
||||
#include "chatlog.h"
|
||||
#include "database.h"
|
||||
#include "client_events.h"
|
||||
#include "config/preferences.h"
|
||||
#include "event/common.h"
|
||||
#include "plugins/plugins.h"
|
||||
#include "ui/inputwin.h"
|
||||
#include "ui/window_list.h"
|
||||
#include "xmpp/chat_session.h"
|
||||
#include "xmpp/session.h"
|
||||
@@ -177,7 +179,7 @@ cl_ev_send_msg_correct(ProfChatWin* chatwin, const char* const msg, const char*
|
||||
#ifdef HAVE_LIBOTR
|
||||
handled = otr_on_message_send(chatwin, message, request_receipt, replace_id);
|
||||
#endif
|
||||
if (!handled) {
|
||||
if (!handled && allow_unencrypted_message(chatwin, message)) {
|
||||
auto_char char* id = message_send_chat(chatwin->barejid, message, oob_url, request_receipt, replace_id);
|
||||
chat_log_msg_out(chatwin->barejid, message, NULL);
|
||||
log_database_add_outgoing_chat(id, chatwin->barejid, message, replace_id, PROF_MSG_ENC_NONE);
|
||||
@@ -251,3 +253,34 @@ cl_ev_send_priv_msg(ProfPrivateWin* privwin, const char* const msg, const char*
|
||||
plugins_post_priv_message_send(privwin->fulljid, message);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
allow_unencrypted_message(ProfChatWin* chatwin, const char* const msg)
|
||||
{
|
||||
if (!prefs_get_boolean(PREF_FORCE_ENCRYPTION)) {
|
||||
return TRUE; // Encryption not enforced
|
||||
}
|
||||
|
||||
auto_gchar gchar* force_enc_mode = prefs_get_string(PREF_FORCE_ENCRYPTION_MODE);
|
||||
|
||||
if (g_strcmp0(force_enc_mode, "block") == 0) {
|
||||
win_println((ProfWin*)chatwin, THEME_ERROR, "-", "Message not sent: encryption required. Enable (omemo/pgp/otr) encryption or /force-encryption off.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (g_strcmp0(force_enc_mode, "resend-to-confirm") == 0) {
|
||||
// We do not use chatwin->last_message because it should be set only if it's sent.
|
||||
guint msg_hash = g_str_hash(msg);
|
||||
if (msg_hash == chatwin->last_attempted_msg_hash) {
|
||||
chatwin->last_attempted_msg_hash = 0; // reset hash
|
||||
return TRUE;
|
||||
}
|
||||
win_println((ProfWin*)chatwin, THEME_ERROR, "-", "Message not sent: encryption required. Enable (omemo/pgp/otr) encryption or press Enter again to send without encryption. Use /force-encryption off to disable this protection.");
|
||||
chatwin->last_attempted_msg_hash = msg_hash;
|
||||
inp_set_line(msg); // reset message to prevent the need to retype it
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
win_println((ProfWin*)chatwin, THEME_ERROR, "-", "Message not sent: invalid encryption mode (%s). Use '/force-encryption policy resend-to-confirm'.", force_enc_mode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -52,4 +52,8 @@ void cl_ev_send_muc_msg_corrected(ProfMucWin* mucwin, const char* const msg, con
|
||||
void cl_ev_send_muc_msg(ProfMucWin* mucwin, const char* const msg, const char* const oob_url);
|
||||
void cl_ev_send_priv_msg(ProfPrivateWin* privwin, const char* const msg, const char* const oob_url);
|
||||
|
||||
// Checks if an unencrypted message can be sent based on encryption preferences.
|
||||
// Returns TRUE if allowed, FALSE if blocked.
|
||||
gboolean allow_unencrypted_message(ProfChatWin* chatwin, const char* const msg);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -424,9 +424,11 @@ chatwin_outgoing_msg(ProfChatWin* chatwin, const char* const message, const char
|
||||
win_print_outgoing((ProfWin*)chatwin, enc_char, id, replace_id, display_message);
|
||||
}
|
||||
|
||||
// save last id and message for LMC in case if it's not LMC message
|
||||
if (id && !replace_id) {
|
||||
_chatwin_set_last_message(chatwin, id, display_message);
|
||||
// Save last id and message for LMC
|
||||
// Note: if the same message is to be corrected several times, the id of the original message is used in each case
|
||||
// https://xmpp.org/extensions/xep-0308.html#rules
|
||||
if (id) {
|
||||
_chatwin_set_last_message(chatwin, replace_id ?: id, display_message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,9 +627,13 @@ chatwin_db_history(ProfChatWin* chatwin, const gchar* start_time, const gchar* e
|
||||
static void
|
||||
_chatwin_set_last_message(ProfChatWin* chatwin, const char* const id, const char* const message)
|
||||
{
|
||||
free(chatwin->last_message);
|
||||
chatwin->last_message = strdup(message);
|
||||
if (message && chatwin->last_message != message) {
|
||||
free(chatwin->last_message);
|
||||
chatwin->last_message = strdup(message);
|
||||
}
|
||||
|
||||
free(chatwin->last_msg_id);
|
||||
chatwin->last_msg_id = strdup(id);
|
||||
if (id && chatwin->last_msg_id != id) {
|
||||
free(chatwin->last_msg_id);
|
||||
chatwin->last_msg_id = strdup(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2891,3 +2891,11 @@ cons_privacy_setting(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cons_encryption_setting(void)
|
||||
{
|
||||
cons_show("Force encryption : %sabled", prefs_get_boolean(PREF_FORCE_ENCRYPTION) ? "en" : "dis");
|
||||
|
||||
cons_show("Force encryption mode : %s", prefs_get_string(PREF_FORCE_ENCRYPTION_MODE));
|
||||
}
|
||||
|
||||
@@ -294,6 +294,14 @@ inp_get_line(void)
|
||||
return line;
|
||||
}
|
||||
|
||||
void
|
||||
inp_set_line(const char* const new_line)
|
||||
{
|
||||
rl_replace_line(new_line, 1);
|
||||
rl_point = rl_end;
|
||||
_inp_redisplay();
|
||||
}
|
||||
|
||||
char*
|
||||
inp_get_password(void)
|
||||
{
|
||||
|
||||
@@ -46,5 +46,6 @@ void inp_win_resize(void);
|
||||
void inp_put_back(void);
|
||||
char* inp_get_password(void);
|
||||
char* inp_get_line(void);
|
||||
void inp_set_line(const char* const new_line);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -289,7 +289,7 @@ void cons_show_disco_info(const char* from, GSList* identities, GSList* features
|
||||
|
||||
void cons_show_disco_contact_information(GHashTable* addresses);
|
||||
|
||||
void cons_show_qrcode();
|
||||
void cons_show_qrcode(const char* const text);
|
||||
|
||||
void cons_show_room_invite(const char* const invitor, const char* const room, const char* const reason);
|
||||
void cons_check_version(gboolean not_available_msg);
|
||||
@@ -351,6 +351,7 @@ void cons_theme_properties(void);
|
||||
void cons_theme_colours(void);
|
||||
void cons_show_tlscert(const TLSCertificate* cert);
|
||||
void cons_show_tlscert_summary(const TLSCertificate* cert);
|
||||
void cons_encryption_setting(void);
|
||||
|
||||
void cons_alert(ProfWin* alert_origin_window);
|
||||
void cons_remove_alert(ProfWin* window);
|
||||
|
||||
@@ -188,6 +188,7 @@ typedef struct prof_chat_win_t
|
||||
char* last_message;
|
||||
char* last_msg_id;
|
||||
gboolean has_attention;
|
||||
guint last_attempted_msg_hash;
|
||||
} ProfChatWin;
|
||||
|
||||
typedef struct prof_muc_win_t
|
||||
|
||||
@@ -164,6 +164,7 @@ win_create_chat(const char* const barejid)
|
||||
new_win->last_message = NULL;
|
||||
new_win->last_msg_id = NULL;
|
||||
new_win->has_attention = FALSE;
|
||||
new_win->last_attempted_msg_hash = 0;
|
||||
new_win->memcheck = PROFCHATWIN_MEMCHECK;
|
||||
|
||||
return &new_win->window;
|
||||
|
||||
@@ -27,6 +27,9 @@ message_send(void **state)
|
||||
assert_true(prof_output_regex("me: .+Hi there"));
|
||||
}
|
||||
|
||||
// TODO: `/message correct` XEP-0308 compliance (whether each correction links to the original message ID)
|
||||
// https://xmpp.org/extensions/xep-0308.html#rules
|
||||
|
||||
void
|
||||
message_receive_console(void **state)
|
||||
{
|
||||
|
||||
@@ -40,3 +40,17 @@ cmd_sub_shows_usage_when_no_arg(void** state)
|
||||
gboolean result = cmd_sub(NULL, CMD_SUB, args);
|
||||
assert_true(result);
|
||||
}
|
||||
|
||||
void
|
||||
test_cmd_sub_malformed_jid(void** state)
|
||||
{
|
||||
ProfWin win;
|
||||
win.type = WIN_CONSOLE;
|
||||
gchar* args[] = { "request", "@example.com" };
|
||||
|
||||
will_return(connection_get_status, JABBER_CONNECTED);
|
||||
|
||||
expect_cons_show("Malformed JID: @example.com");
|
||||
gboolean result = cmd_sub((ProfWin*)&win, CMD_SUB, args);
|
||||
assert_true(result);
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
void cmd_sub_shows_message_when_not_connected(void** state);
|
||||
void cmd_sub_shows_usage_when_no_arg(void** state);
|
||||
void test_cmd_sub_malformed_jid(void** state);
|
||||
135
tests/unittests/test_forced_encryption.c
Normal file
135
tests/unittests/test_forced_encryption.c
Normal file
@@ -0,0 +1,135 @@
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <cmocka.h>
|
||||
#include <glib.h>
|
||||
#include "event/client_events.h"
|
||||
#include "command/cmd_funcs.h"
|
||||
#include "config/preferences.h"
|
||||
#include "ui/stub_ui.h"
|
||||
|
||||
#define CMD_FORCE_ENCRYPTION "/force-encryption"
|
||||
|
||||
// Test: /force-encryption with no arguments shows error.
|
||||
void
|
||||
test_cmd_force_encryption_no_args_bad_cmd(void** state)
|
||||
{
|
||||
char* args[] = { NULL };
|
||||
expect_string(cons_bad_cmd_usage, cmd, CMD_FORCE_ENCRYPTION);
|
||||
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
|
||||
}
|
||||
|
||||
// Test: /force-encryption on enables encryption.
|
||||
void
|
||||
test_cmd_force_encryption_toggles_on(void** state)
|
||||
{
|
||||
prefs_set_boolean(PREF_FORCE_ENCRYPTION, FALSE);
|
||||
char* args[] = { "on", NULL };
|
||||
expect_cons_show("Forces encryption enabled.");
|
||||
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
|
||||
assert_true(prefs_get_boolean(PREF_FORCE_ENCRYPTION));
|
||||
}
|
||||
|
||||
// Test: /force-encryption off disables encryption.
|
||||
void
|
||||
test_cmd_force_encryption_toggles_off(void** state)
|
||||
{
|
||||
prefs_set_boolean(PREF_FORCE_ENCRYPTION, TRUE);
|
||||
char* args[] = { "off", NULL };
|
||||
expect_cons_show("Forces encryption disabled.");
|
||||
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
|
||||
assert_false(prefs_get_boolean(PREF_FORCE_ENCRYPTION));
|
||||
}
|
||||
|
||||
// Test: /force-encryption off when already off.
|
||||
void
|
||||
test_cmd_force_encryption_toggles_off_already(void** state)
|
||||
{
|
||||
prefs_set_boolean(PREF_FORCE_ENCRYPTION, FALSE);
|
||||
char* args[] = { "off", NULL };
|
||||
expect_cons_show("Forces encryption is already disabled.");
|
||||
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
|
||||
assert_false(prefs_get_boolean(PREF_FORCE_ENCRYPTION));
|
||||
}
|
||||
|
||||
// Test: /force-encryption on when already on.
|
||||
void
|
||||
test_cmd_force_encryption_toggles_on_already(void** state)
|
||||
{
|
||||
prefs_set_boolean(PREF_FORCE_ENCRYPTION, TRUE);
|
||||
char* args[] = { "on", NULL };
|
||||
expect_cons_show("Forces encryption is already enabled.");
|
||||
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
|
||||
assert_true(prefs_get_boolean(PREF_FORCE_ENCRYPTION));
|
||||
}
|
||||
|
||||
// Test: /force-encryption policy block sets block mode.
|
||||
void
|
||||
test_cmd_force_encryption_sets_policy_block(void** state)
|
||||
{
|
||||
char* args[] = { "policy", "block", NULL };
|
||||
expect_cons_show("Force encryption policy has been set to \"block\".");
|
||||
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
|
||||
auto_gchar gchar* pref_force_enc_mode = prefs_get_string(PREF_FORCE_ENCRYPTION_MODE);
|
||||
assert_string_equal(pref_force_enc_mode, "block");
|
||||
}
|
||||
|
||||
// Test: /force-encryption policy resend-to-confirm sets resend mode.
|
||||
void
|
||||
test_cmd_force_encryption_sets_policy_resend(void** state)
|
||||
{
|
||||
char* args[] = { "policy", "resend-to-confirm", NULL };
|
||||
expect_cons_show("Force encryption policy has been set to \"resend-to-confirm\".");
|
||||
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
|
||||
auto_gchar gchar* pref_force_enc_mode = prefs_get_string(PREF_FORCE_ENCRYPTION_MODE);
|
||||
assert_string_equal(pref_force_enc_mode, "resend-to-confirm");
|
||||
}
|
||||
|
||||
// Test: Unencrypted message blocked when policy is block.
|
||||
void
|
||||
test_allow_unencrypted_message_blocks(void** state)
|
||||
{
|
||||
prefs_set_boolean(PREF_FORCE_ENCRYPTION, TRUE);
|
||||
prefs_set_string(PREF_FORCE_ENCRYPTION_MODE, "block");
|
||||
ProfChatWin win = {};
|
||||
char* msg = "test message";
|
||||
expect_win_println("Message not sent: encryption required. Enable (omemo/pgp/otr) encryption or /force-encryption off.");
|
||||
assert_false(allow_unencrypted_message(&win, msg));
|
||||
}
|
||||
|
||||
// Test: Unencrypted message prompts confirmation, then allows on second attempt.
|
||||
void
|
||||
test_allow_unencrypted_message_confirms_on_second_attempt(void** state)
|
||||
{
|
||||
prefs_set_boolean(PREF_FORCE_ENCRYPTION, TRUE);
|
||||
prefs_set_string(PREF_FORCE_ENCRYPTION_MODE, "resend-to-confirm");
|
||||
ProfChatWin win = { .last_attempted_msg_hash = 0 };
|
||||
char* msg = "test message";
|
||||
expect_win_println("Message not sent: encryption required. Enable (omemo/pgp/otr) encryption or press Enter again to send without encryption. Use /force-encryption off to disable this protection.");
|
||||
assert_false(allow_unencrypted_message(&win, msg));
|
||||
assert_int_not_equal(win.last_attempted_msg_hash, 0);
|
||||
assert_true(allow_unencrypted_message(&win, msg));
|
||||
assert_int_equal(win.last_attempted_msg_hash, 0); // ensure that value resets since we don't want to approve the same message twice
|
||||
}
|
||||
|
||||
// Test: Invalid policy argument fails gracefully.
|
||||
void
|
||||
test_cmd_force_encryption_invalid_policy(void** state)
|
||||
{
|
||||
char* args[] = { "policy", "invalid", NULL };
|
||||
expect_cons_show_error("Invalid policy: \"invalid\". See '/help force-encryption' for details.");
|
||||
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
|
||||
}
|
||||
|
||||
// Test: Invalid encryption mode blocks message.
|
||||
void
|
||||
test_allow_unencrypted_message_invalid_mode(void** state)
|
||||
{
|
||||
prefs_set_boolean(PREF_FORCE_ENCRYPTION, TRUE);
|
||||
prefs_set_string(PREF_FORCE_ENCRYPTION_MODE, "invalid");
|
||||
ProfChatWin win = { .last_attempted_msg_hash = 0 };
|
||||
char* msg = "test message";
|
||||
expect_win_println("Message not sent: invalid encryption mode (invalid). Use '/force-encryption policy resend-to-confirm'.");
|
||||
assert_false(allow_unencrypted_message(&win, msg));
|
||||
assert_int_equal(win.last_attempted_msg_hash, 0);
|
||||
}
|
||||
16
tests/unittests/test_forced_encryption.h
Normal file
16
tests/unittests/test_forced_encryption.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef TEST_FORCED_ENCRYPTION_H
|
||||
#define TEST_FORCED_ENCRYPTION_H
|
||||
|
||||
void test_cmd_force_encryption_no_args_bad_cmd(void** state);
|
||||
void test_cmd_force_encryption_toggles_on(void** state);
|
||||
void test_cmd_force_encryption_toggles_off(void** state);
|
||||
void test_cmd_force_encryption_toggles_off_already(void** state);
|
||||
void test_cmd_force_encryption_toggles_on_already(void** state);
|
||||
void test_cmd_force_encryption_sets_policy_block(void** state);
|
||||
void test_cmd_force_encryption_sets_policy_resend(void** state);
|
||||
void test_allow_unencrypted_message_blocks(void** state);
|
||||
void test_allow_unencrypted_message_confirms_on_second_attempt(void** state);
|
||||
void test_cmd_force_encryption_invalid_policy(void** state);
|
||||
void test_allow_unencrypted_message_invalid_mode(void** state);
|
||||
|
||||
#endif // TEST_FORCED_ENCRYPTION_H
|
||||
@@ -675,6 +675,11 @@ inp_readline(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
inp_set_line(const char* const new_line)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
inp_nonblocking(gboolean reset)
|
||||
{
|
||||
@@ -1157,6 +1162,11 @@ cons_privacy_setting(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
cons_encryption_setting(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
cons_show_bookmarks_ignore(gchar** list, gsize len)
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "test_cmd_presence.h"
|
||||
#include "test_cmd_otr.h"
|
||||
#include "test_cmd_pgp.h"
|
||||
#include "test_forced_encryption.h"
|
||||
#include "test_jid.h"
|
||||
#include "test_parser.h"
|
||||
#include "test_roster_list.h"
|
||||
@@ -385,6 +386,7 @@ main(int argc, char* argv[])
|
||||
|
||||
cmocka_unit_test(cmd_sub_shows_message_when_not_connected),
|
||||
cmocka_unit_test(cmd_sub_shows_usage_when_no_arg),
|
||||
cmocka_unit_test(test_cmd_sub_malformed_jid),
|
||||
|
||||
cmocka_unit_test(contact_in_group),
|
||||
cmocka_unit_test(contact_not_in_group),
|
||||
@@ -644,6 +646,19 @@ main(int argc, char* argv[])
|
||||
cmocka_unit_test(does_not_add_duplicate_feature),
|
||||
cmocka_unit_test(removes_plugin_features),
|
||||
cmocka_unit_test(does_not_remove_feature_when_more_than_one_reference),
|
||||
|
||||
// Forced encryption
|
||||
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_no_args_bad_cmd, load_preferences, close_preferences),
|
||||
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_toggles_on, load_preferences, close_preferences),
|
||||
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_toggles_off, load_preferences, close_preferences),
|
||||
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_toggles_off_already, load_preferences, close_preferences),
|
||||
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_toggles_on_already, load_preferences, close_preferences),
|
||||
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_sets_policy_block, load_preferences, close_preferences),
|
||||
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_sets_policy_resend, load_preferences, close_preferences),
|
||||
cmocka_unit_test_setup_teardown(test_allow_unencrypted_message_blocks, load_preferences, close_preferences),
|
||||
cmocka_unit_test_setup_teardown(test_allow_unencrypted_message_confirms_on_second_attempt, load_preferences, close_preferences),
|
||||
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_invalid_policy, load_preferences, close_preferences),
|
||||
cmocka_unit_test_setup_teardown(test_allow_unencrypted_message_invalid_mode, load_preferences, close_preferences),
|
||||
};
|
||||
return cmocka_run_group_tests(all_tests, NULL, NULL);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user