From deb32bded40c4c46ce57c729c303edcb1915458b Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 8 Nov 2022 22:05:03 +0100 Subject: html parser: fix possible endless loop. Fixes matrix chat where parsing non-html as html happened --- depends/html-parser | 2 +- depends/html-search | 2 +- plugins/Matrix.hpp | 2 +- src/QuickMedia.cpp | 12 +++++++-- src/plugins/Matrix.cpp | 71 ++++++++++++++++++++++++++++++++++---------------- 5 files changed, 62 insertions(+), 27 deletions(-) diff --git a/depends/html-parser b/depends/html-parser index 684a3bc..66ec83b 160000 --- a/depends/html-parser +++ b/depends/html-parser @@ -1 +1 @@ -Subproject commit 684a3bc56d5c40ed3eb54ca263751fa4724e73fa +Subproject commit 66ec83b862ea2a8dbda1c1f3663af88a8d12d9bc diff --git a/depends/html-search b/depends/html-search index 3dbbcc7..0dd5817 160000 --- a/depends/html-search +++ b/depends/html-search @@ -1 +1 @@ -Subproject commit 3dbbcc75199bd996163500beb39a6e902bc7ddc4 +Subproject commit 0dd5817eecb3a8db9338394e2c164119a92d4dba diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp index 4afe28e..ac3ca3b 100644 --- a/plugins/Matrix.hpp +++ b/plugins/Matrix.hpp @@ -20,7 +20,6 @@ namespace QuickMedia { static const int AUTHOR_MAX_LENGTH = 48; - std::string remove_reply_formatting(const std::string &str); std::string extract_first_line_remove_newline_elipses(const std::string &str, size_t max_length); mgl::Color user_id_to_color(const std::string &user_id); std::string formatted_text_to_qm_text(const char *str, size_t size, bool allow_formatted_text); @@ -103,6 +102,7 @@ namespace QuickMedia { RelatedEventType related_event_type = RelatedEventType::NONE; bool notification_mentions_me = false; bool cache = false; + bool body_is_formatted = false; std::string transaction_id; time_t timestamp = 0; // In milliseconds MessageType type; diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 72df6eb..c9c7603 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -5319,10 +5319,17 @@ namespace QuickMedia { return load_cached_related_embedded_item(body_item, message, me.get(), current_room->get_user_display_name(me), me->user_id, message_body_items); } + static std::string message_to_qm_text(Message *message) { + if(message->body_is_formatted) + return formatted_text_to_qm_text(message->body.c_str(), message->body.size(), true); + else + return message->body; + } + static std::shared_ptr message_to_body_item(RoomData *room, Message *message, const std::string &my_display_name, const std::string &my_user_id) { auto body_item = BodyItem::create(""); body_item->set_author(extract_first_line_remove_newline_elipses(room->get_user_display_name(message->user), AUTHOR_MAX_LENGTH)); - body_item->set_description(strip(formatted_text_to_qm_text(message->body.c_str(), message->body.size(), true))); + body_item->set_description(strip(message_to_qm_text(message))); body_item->set_timestamp(message->timestamp); if(!message->thumbnail_url.empty()) { body_item->thumbnail_url = message->thumbnail_url; @@ -5652,7 +5659,7 @@ namespace QuickMedia { // TODO: Properly check reply message objects for mention of user instead of message data, but only when synapse fixes that notifications // are not triggered by reply to a message with our display name/user id. Message *edited_message_ref = static_cast(body_item->userdata); - std::string qm_formatted_text = formatted_text_to_qm_text(message->body.c_str(), message->body.size(), true); + std::string qm_formatted_text = message_to_qm_text(message.get()); body_item->set_description(std::move(qm_formatted_text)); if(message->user != me && message_contains_user_mention(message.get(), my_display_name, me->user_id)) @@ -6116,6 +6123,7 @@ namespace QuickMedia { } auto message = std::make_shared(); + message->body_is_formatted = true; message->user = matrix->get_me(current_room); if(msgtype == "m.emote") message->body = "*" + current_room->get_user_display_name(me) + "* " + matrix->body_to_formatted_body(current_room, text); diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index d1a060d..31aab76 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -117,6 +117,34 @@ namespace QuickMedia { return colors[color_hash_code(user_id) % num_colors]; } + static std::string remove_reply_formatting(const std::string &str) { + if(strncmp(str.c_str(), "> <@", 4) == 0) { + size_t index = str.find("> ", 4); + if(index != std::string::npos) { + size_t msg_begin = str.find("\n\n", index + 2); + if(msg_begin != std::string::npos) + return str.substr(msg_begin + 2); + } + } else { + return formatted_text_to_qm_text(str.c_str(), str.size(), false); + } + return str; + } + + static std::string remove_reply_formatting(const Message *message) { + if(!message->body_is_formatted && strncmp(message->body.c_str(), "> <@", 4) == 0) { + size_t index = message->body.find("> ", 4); + if(index != std::string::npos) { + size_t msg_begin = message->body.find("\n\n", index + 2); + if(msg_begin != std::string::npos) + return message->body.substr(msg_begin + 2); + } + return message->body; + } else { + return formatted_text_to_qm_text(message->body.c_str(), message->body.size(), false); + } + } + bool TimestampedDisplayData::set_data_if_newer(std::string new_data, time_t new_timestamp) { if(new_timestamp == 0) { data = std::move(new_data); @@ -433,7 +461,7 @@ namespace QuickMedia { if(!sync_is_cache && message_dir == MessageDirection::AFTER) { for(auto &message : messages) { if(message->notification_mentions_me) { - std::string body = remove_reply_formatting(message->body); + std::string body = remove_reply_formatting(message.get()); bool read = true; // TODO: What if the message or username begins with "-"? also make the notification image be the avatar of the user if((!is_window_focused || room != current_room) && message->related_event_type != RelatedEventType::EDIT && message->related_event_type != RelatedEventType::REDACTION) { @@ -598,8 +626,15 @@ namespace QuickMedia { return nullptr; } + static std::string message_to_qm_text(const Message *message, bool allow_formatted_text = true) { + if(message->body_is_formatted) + return formatted_text_to_qm_text(message->body.c_str(), message->body.size(), allow_formatted_text); + else + return message->body; + } + static std::string message_to_room_description_text(Message *message) { - std::string body = strip(formatted_text_to_qm_text(message->body.c_str(), message->body.size(), true)); + std::string body = strip(message_to_qm_text(message)); if(message->type == MessageType::REACTION) return "Reacted with: " + body; else if(message->related_event_type == RelatedEventType::REPLY) @@ -2130,7 +2165,7 @@ namespace QuickMedia { } bool message_contains_user_mention(const Message *message, const std::string &username, const std::string &user_id) { - const std::string formatted_text = formatted_text_to_qm_text(message->body.c_str(), message->body.size(), false); + const std::string formatted_text = message_to_qm_text(message, false); return message_contains_user_mention(formatted_text, username) || message_contains_user_mention(formatted_text, user_id); } @@ -2197,7 +2232,7 @@ namespace QuickMedia { // TODO: Is @room ok? shouldn't we also check if the user has permission to do @room? (only when notifications are limited to @mentions) // TODO: Is comparing against read marker timestamp ok enough? if(me && message->timestamp > read_marker_message_timestamp) { - std::string message_str = formatted_text_to_qm_text(message->body.c_str(), message->body.size(), false); + std::string message_str = message_to_qm_text(message.get(), false); message->notification_mentions_me = message_contains_user_mention(message_str, my_display_name) || message_contains_user_mention(message_str, me->user_id) || message_contains_user_mention(message_str, "@room"); } } @@ -2370,8 +2405,10 @@ namespace QuickMedia { code_parse_userdata.allow_formatted_text = true; code_parse_userdata.inside_source_highlight = true; html_parser_parse(output.c_str(), output.size(), formattext_text_parser_callback, &code_parse_userdata); - text_to_add = std::move(code_parse_userdata.result); - formatted_text_flags = FORMATTED_TEXT_FLAG_NONE; + if(!code_parse_userdata.result.empty()) { + text_to_add = std::move(code_parse_userdata.result); + formatted_text_flags = FORMATTED_TEXT_FLAG_NONE; + } } } } @@ -2775,9 +2812,12 @@ namespace QuickMedia { if(!body_json.IsString()) return nullptr; + bool body_is_formatted = true; const rapidjson::Value *formatted_body_json = &GetMember(*content_json, "formatted_body"); - if(!formatted_body_json->IsString()) + if(!formatted_body_json->IsString()) { formatted_body_json = &body_json; + body_is_formatted = false; + } auto message = std::make_shared(); std::string prefix; @@ -2846,6 +2886,7 @@ namespace QuickMedia { message->user = user; message->event_id = event_id_str; message->body = prefix + std::string(formatted_body_json->GetString(), formatted_body_json->GetStringLength()); + message->body_is_formatted = body_is_formatted; message->related_event_id = std::move(related_event_id); message->related_event_type = related_event_type; message->timestamp = timestamp; @@ -3567,20 +3608,6 @@ namespace QuickMedia { return PluginResult::OK; } - std::string remove_reply_formatting(const std::string &str) { - if(strncmp(str.c_str(), "> <@", 4) == 0) { - size_t index = str.find("> ", 4); - if(index != std::string::npos) { - size_t msg_begin = str.find("\n\n", index + 2); - if(msg_begin != std::string::npos) - return str.substr(msg_begin + 2); - } - } else { - return formatted_text_to_qm_text(str.c_str(), str.size(), false); - } - return str; - } - static std::string block_quote(const std::string &str) { std::string result; for(char c : str) { @@ -3600,7 +3627,7 @@ namespace QuickMedia { switch(message->type) { case MessageType::TEXT: { if(message->related_event_type != RelatedEventType::NONE) - related_to_body = remove_reply_formatting(message->body); + related_to_body = remove_reply_formatting(message); else related_to_body = message->body; break; -- cgit v1.2.3