feat: sanitize illegal XML characters from outgoing messages (upstream 189050f3)
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -114,3 +114,4 @@ coverage/
|
||||
*.gcda
|
||||
*.gcov
|
||||
coverage.info
|
||||
REVIEW.txt
|
||||
|
||||
27
src/common.c
27
src/common.c
@@ -380,6 +380,33 @@ utf8_display_len(const char* const str)
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes illegal XML 1.0 characters from a string.
|
||||
*
|
||||
* This function creates a new string that excludes characters in the range
|
||||
* U+0000 to U+001F, except for U+0009 (TAB), U+000A (LF), and U+000D (CR).
|
||||
*/
|
||||
gchar*
|
||||
str_xml_sanitize(const char* const str)
|
||||
{
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GString* sanitized = g_string_new_len(NULL, strlen(str));
|
||||
const char* curr = str;
|
||||
|
||||
while (*curr != '\0') {
|
||||
gunichar c = g_utf8_get_char(curr);
|
||||
if ((c >= 0x20) || (c == 0x09) || (c == 0x0A) || (c == 0x0D)) {
|
||||
g_string_append_unichar(sanitized, c);
|
||||
}
|
||||
curr = g_utf8_next_char(curr);
|
||||
}
|
||||
|
||||
return g_string_free(sanitized, FALSE);
|
||||
}
|
||||
|
||||
char*
|
||||
release_get_latest(void)
|
||||
{
|
||||
|
||||
@@ -180,6 +180,7 @@ gboolean copy_file(const char* const src, const char* const target, const gboole
|
||||
char* str_replace(const char* string, const char* substr, const char* replacement);
|
||||
gboolean strtoi_range(const char* str, int* saveptr, int min, int max, char** err_msg);
|
||||
int utf8_display_len(const char* const str);
|
||||
gchar* str_xml_sanitize(const char* const str);
|
||||
|
||||
char* release_get_latest(void);
|
||||
gboolean release_is_new(char* found_version);
|
||||
|
||||
@@ -139,7 +139,8 @@ cl_ev_send_msg_correct(ProfChatWin* chatwin, const char* const msg, const char*
|
||||
gboolean request_receipt = prefs_get_boolean(PREF_RECEIPTS_REQUEST);
|
||||
|
||||
auto_char char* plugin_msg = plugins_pre_chat_message_send(chatwin->barejid, msg);
|
||||
const char* const message = plugin_msg ?: msg;
|
||||
auto_gchar gchar* sanitized_msg = str_xml_sanitize(plugin_msg ?: msg);
|
||||
const char* message = sanitized_msg;
|
||||
|
||||
char* replace_id = NULL;
|
||||
if (correct_last_msg) {
|
||||
@@ -201,7 +202,8 @@ void
|
||||
cl_ev_send_muc_msg_corrected(ProfMucWin* mucwin, const char* const msg, const char* const oob_url, gboolean correct_last_msg)
|
||||
{
|
||||
auto_char char* plugin_msg = plugins_pre_room_message_send(mucwin->roomjid, msg);
|
||||
const char* const message = plugin_msg ?: msg;
|
||||
auto_gchar gchar* sanitized_msg = str_xml_sanitize(plugin_msg ?: msg);
|
||||
const char* message = sanitized_msg;
|
||||
|
||||
char* replace_id = NULL;
|
||||
if (correct_last_msg) {
|
||||
@@ -242,7 +244,8 @@ cl_ev_send_priv_msg(ProfPrivateWin* privwin, const char* const msg, const char*
|
||||
privwin_message_left_room(privwin);
|
||||
} else {
|
||||
auto_char char* plugin_msg = plugins_pre_priv_message_send(privwin->fulljid, msg);
|
||||
const char* const message = plugin_msg ?: msg;
|
||||
auto_gchar gchar* sanitized_msg = str_xml_sanitize(plugin_msg ?: msg);
|
||||
const char* message = sanitized_msg;
|
||||
auto_jid Jid* jidp = jid_create(privwin->fulljid);
|
||||
|
||||
auto_char char* id = message_send_private(privwin->fulljid, message, oob_url);
|
||||
|
||||
@@ -846,3 +846,35 @@ prof_whole_occurrences_tests(void** state)
|
||||
g_slist_free(expected);
|
||||
expected = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
str_xml_sanitize__strips_illegal_characters(void** state)
|
||||
{
|
||||
// Test NULL input
|
||||
assert_null(str_xml_sanitize(NULL));
|
||||
|
||||
// Test empty string
|
||||
gchar* res1 = str_xml_sanitize("");
|
||||
assert_string_equal("", res1);
|
||||
g_free(res1);
|
||||
|
||||
// Test string with no illegal characters
|
||||
gchar* res2 = str_xml_sanitize("Hello World! \t\n\r");
|
||||
assert_string_equal("Hello World! \t\n\r", res2);
|
||||
g_free(res2);
|
||||
|
||||
// Test string with illegal characters (0x16 is ^V, 0x01 is ^A)
|
||||
gchar* res3 = str_xml_sanitize("Hello\x16World\x01!");
|
||||
assert_string_equal("HelloWorld!", res3);
|
||||
g_free(res3);
|
||||
|
||||
// Test string with mixed legal and illegal control characters
|
||||
gchar* res4 = str_xml_sanitize("\x09Legal\x0BIllegal\x0ALegal\x1FIllegal\x0DLegal");
|
||||
assert_string_equal("\tLegalIllegal\nLegalIllegal\rLegal", res4);
|
||||
g_free(res4);
|
||||
|
||||
// Test UTF-8 characters
|
||||
gchar* res5 = str_xml_sanitize("UTF-8: üñîçøðé \x16 and more");
|
||||
assert_string_equal("UTF-8: üñîçøðé and more", res5);
|
||||
g_free(res5);
|
||||
}
|
||||
|
||||
@@ -34,3 +34,4 @@ void prof_whole_occurrences_tests(void** state);
|
||||
void prof_occurrences_of_large_message_tests(void** state);
|
||||
void unique_filename_from_url_td(void** state);
|
||||
void format_call_external_argv_td(void** state);
|
||||
void str_xml_sanitize__strips_illegal_characters(void** state);
|
||||
|
||||
@@ -628,6 +628,7 @@ main(int argc, char* argv[])
|
||||
cmocka_unit_test(prof_partial_occurrences_tests),
|
||||
cmocka_unit_test(prof_whole_occurrences_tests),
|
||||
cmocka_unit_test(prof_occurrences_of_large_message_tests),
|
||||
cmocka_unit_test(str_xml_sanitize__strips_illegal_characters),
|
||||
|
||||
cmocka_unit_test_setup_teardown(returns_no_commands,
|
||||
load_preferences,
|
||||
|
||||
Reference in New Issue
Block a user