widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #06998
[Merge] lp:~widelands-dev/widelands/escaping-fixes into lp:widelands
Miroslav Remák has proposed merging lp:~widelands-dev/widelands/escaping-fixes into lp:widelands.
Commit message:
- Introduce '&' entity which translates to '&'
- Properly escape user messages
- Fix entity replacement in the old RT renderer
- Use a function for repeated code in chat_msg_layout.cc
Requested reviews:
Widelands Developers (widelands-dev)
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/escaping-fixes/+merge/290410
This allows the user to type e.g. '<' literally, and fixes input fields getting messed up when such entity is typed in. It also prevents crashes (uncaught exceptions) with certain nicknames such as '<'.
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/escaping-fixes into lp:widelands.
=== modified file 'src/graphic/richtext.cc'
--- src/graphic/richtext.cc 2016-03-02 17:11:16 +0000
+++ src/graphic/richtext.cc 2016-03-30 08:43:17 +0000
@@ -86,7 +86,6 @@
for (std::vector<std::string>::iterator source_it = words.begin();
source_it != words.end(); ++source_it) {
std::string& word = *source_it;
- replace_entities(&word);
if (source_it != words.end()) {
if (i18n::has_rtl_character(word.c_str()) || i18n::has_rtl_character(previous_word.c_str())) {
it = result_words.insert(result_words.begin(), word);
@@ -101,7 +100,6 @@
}
} else {
for (std::string& word: words) {
- replace_entities(&word);
result_words.push_back(word);
}
}
=== modified file 'src/graphic/text_layout.cc'
--- src/graphic/text_layout.cc 2016-03-14 19:49:52 +0000
+++ src/graphic/text_layout.cc 2016-03-30 08:43:17 +0000
@@ -36,6 +36,7 @@
boost::replace_all(*text, ">", ">");
boost::replace_all(*text, "<", "<");
boost::replace_all(*text, " ", " ");
+ boost::replace_all(*text, "&", "&"); // Must be performed last
}
uint32_t text_width(const std::string& text, int ptsize) {
@@ -49,6 +50,7 @@
std::string richtext_escape(const std::string& given_text) {
std::string text = given_text;
+ boost::replace_all(text, "&", "&"); // Must be performed first
boost::replace_all(text, ">", ">");
boost::replace_all(text, "<", "<");
return text;
=== modified file 'src/graphic/text_parser.cc'
--- src/graphic/text_parser.cc 2016-03-14 19:49:52 +0000
+++ src/graphic/text_parser.cc 2016-03-30 08:43:17 +0000
@@ -28,6 +28,7 @@
#include "graphic/font_handler1.h"
#include "graphic/text/bidi.h"
#include "graphic/text/font_set.h"
+#include "graphic/text_layout.h"
#include "helper.h"
namespace UI {
@@ -135,11 +136,17 @@
}
if (next_break == std::string::npos) {
- if (line.size())
- words.push_back(line);
+ if (line.size()) {
+ std::string word = line;
+ replace_entities(&word);
+ words.push_back(word);
+ }
break;
- } else if (next_break)
- words.push_back(line.substr(0, next_break));
+ } else if (next_break) {
+ std::string word = line.substr(0, next_break);
+ replace_entities(&word);
+ words.push_back(word);
+ }
line_breaks.push_back(words.size());
line.erase(0, next_break + 4);
}
=== modified file 'src/wui/chat_msg_layout.cc'
--- src/wui/chat_msg_layout.cc 2016-03-28 10:37:09 +0000
+++ src/wui/chat_msg_layout.cc 2016-03-30 08:43:17 +0000
@@ -23,6 +23,7 @@
#include "chat/chat.h"
#include "graphic/color.h"
+#include "graphic/text_layout.h"
#include "logic/constants.h"
#include "logic/player.h"
@@ -47,44 +48,7 @@
const std::string& font_face = "serif";
std::string message = "<p font-color=#33ff33 font-size=9>";
- // Escape richtext characters
- // The goal of this code is two-fold:
- // 1. Assuming an honest game host, we want to prevent the ability of
- // clients to use richtext.
- // 2. Assuming a malicious host or meta server, we want to reduce the
- // likelihood that a bug in the richtext renderer can be exploited,
- // by restricting the set of allowed richtext commands.
- // Most notably, images are not allowed in richtext at all.
- //
- // Note that we do want host and meta server to send some richtext code,
- // as the ability to send formatted commands is nice for the usability
- // of meta server so we're treading a bit of a fine line here.
- std::string sanitized;
- for (std::string::size_type pos = 0; pos < chat_message.msg.size(); ++pos) {
- if (chat_message.msg[pos] == '<') {
- if (chat_message.playern < 0) {
- static const std::string good1 = "</p><p";
- static const std::string good2 = "<br>";
- if (!chat_message.msg.compare(pos, good1.size(), good1)) {
- std::string::size_type nextclose = chat_message.msg.find('>', pos + good1.size());
- if (nextclose != std::string::npos &&
- (nextclose == pos + good1.size() || chat_message.msg[pos + good1.size()] == ' ')) {
- sanitized += good1;
- pos += good1.size() - 1;
- continue;
- }
- } else if (!chat_message.msg.compare(pos, good2.size(), good2)) {
- sanitized += good2;
- pos += good2.size() - 1;
- continue;
- }
- }
-
- sanitized += "<";
- } else {
- sanitized += chat_message.msg[pos];
- }
- }
+ std::string sanitized = sanitize_message(chat_message);
// time calculation
char ts[13];
@@ -94,32 +58,35 @@
message = (boost::format("%s<p font-size=14 font-face=%s font-color=#%s")
% message % font_face % color(chat_message.playern)).str();
+ std::string sender_escaped = richtext_escape(chat_message.sender);
+ std::string recipient_escaped = richtext_escape(chat_message.recipient);
+
if (chat_message.recipient.size() && chat_message.sender.size()) {
// Personal message handling
if (sanitized.compare(0, 3, "/me")) {
message = (boost::format("%s font-decoration=underline>%s @ %s:</p><p font-size=14 font-face=%s> %s")
% message
- % chat_message.sender
- % chat_message.recipient
+ % sender_escaped
+ % recipient_escaped
% font_face
% sanitized).str();
} else {
message =
- (boost::format("%s>@%s >> </p>"
+ (boost::format("%s>@%s >> </p>"
"<p font-size=14 font-face=%s font-color=#%s font-style=italic> %s%s")
% message
- % chat_message.recipient
+ % recipient_escaped
% font_face
% color(chat_message.playern)
- % chat_message.sender
+ % sender_escaped
% sanitized.substr(3)).str();
}
} else {
// Normal messages handling
if (!sanitized.compare(0, 3, "/me")) {
- message = (boost::format("%s font-style=italic>-> %s%s")
+ message = (boost::format("%s font-style=italic>-> %s%s")
% message
% (chat_message.sender.size() ? chat_message.sender.c_str() : "***")
% sanitized.substr(3)).str();
@@ -127,7 +94,7 @@
} else if (chat_message.sender.size()) {
message = (boost::format("%s font-decoration=underline>%s:</p><p font-size=14 font-face=%s> %s")
% message
- % chat_message.sender
+ % sender_escaped
% font_face
% sanitized).str();
} else {
@@ -145,46 +112,7 @@
const std::string& font_face = "serif";
std::string message = "<p><font color=33ff33 size=9>";
- // Escape richtext characters
- // The goal of this code is two-fold:
- // 1. Assuming an honest game host, we want to prevent the ability of
- // clients to use richtext.
- // 2. Assuming a malicious host or meta server, we want to reduce the
- // likelihood that a bug in the richtext renderer can be exploited,
- // by restricting the set of allowed richtext commands.
- // Most notably, images are not allowed in richtext at all.
- //
- // Note that we do want host and meta server to send some richtext code,
- // as the ability to send formatted commands is nice for the usability
- // of meta server so we're treading a bit of a fine line here.
- std::string sanitized;
- for (std::string::size_type pos = 0; pos < chat_message.msg.size(); ++pos) {
- if (chat_message.msg[pos] == '<') {
- if (chat_message.playern < 0) {
- static const std::string good1 = "</p><p";
- static const std::string good2 = "<br>";
- if (!chat_message.msg.compare(pos, good1.size(), good1)) {
- std::string::size_type nextclose = chat_message.msg.find('>', pos + good1.size());
- if
- (nextclose != std::string::npos &&
- (nextclose == pos + good1.size() || chat_message.msg[pos + good1.size()] == ' '))
- {
- sanitized += good1;
- pos += good1.size() - 1;
- continue;
- }
- } else if (!chat_message.msg.compare(pos, good2.size(), good2)) {
- sanitized += good2;
- pos += good2.size() - 1;
- continue;
- }
- }
-
- sanitized += "<";
- } else {
- sanitized += chat_message.msg[pos];
- }
- }
+ std::string sanitized = sanitize_message(chat_message);
// time calculation
char ts[13];
@@ -194,23 +122,26 @@
message = (boost::format("%s</font><font size=14 face=%s color=%s")
% message % font_face % color(chat_message.playern)).str();
+ std::string sender_escaped = richtext_escape(chat_message.sender);
+ std::string recipient_escaped = richtext_escape(chat_message.recipient);
+
if (chat_message.recipient.size() && chat_message.sender.size()) {
// Personal message handling
if (sanitized.compare(0, 3, "/me")) {
message = (boost::format("%s bold=1>%s @ %s:</font><font size=14 face=%s shadow=1 color=eeeeee> %s")
% message
- % chat_message.sender
- % chat_message.recipient
+ % sender_escaped
+ % recipient_escaped
% font_face
% sanitized).str();
} else {
message = (boost::format("%s>@%s > </font><font size=14 face=%s color=%s italic=1 shadow=1> %s%s")
% message
- % chat_message.recipient
+ % recipient_escaped
% font_face
% color(chat_message.playern)
- % chat_message.sender
+ % sender_escaped
% sanitized.substr(3)).str();
}
} else {
@@ -218,14 +149,14 @@
if (!sanitized.compare(0, 3, "/me")) {
message += " italic=1>-> ";
if (chat_message.sender.size())
- message += chat_message.sender;
+ message += sender_escaped;
else
message += "***";
message += sanitized.substr(3);
} else if (chat_message.sender.size()) {
message = (boost::format("%s bold=1>%s:</font><font size=14 face=%s shadow=1 color=eeeeee> %s")
% message
- % chat_message.sender
+ % sender_escaped
% font_face
% sanitized).str();
} else {
@@ -237,3 +168,52 @@
// return the formated message
return message + "</font><br></p>";
}
+
+std::string sanitize_message(const ChatMessage & chat_message)
+{
+ // Escape richtext characters
+ // The goal of this code is two-fold:
+ // 1. Assuming an honest game host, we want to prevent the ability of
+ // clients to use richtext.
+ // 2. Assuming a malicious host or meta server, we want to reduce the
+ // likelihood that a bug in the richtext renderer can be exploited,
+ // by restricting the set of allowed richtext commands.
+ // Most notably, images are not allowed in richtext at all.
+ //
+ // Note that we do want host and meta server to send some richtext code,
+ // as the ability to send formatted commands is nice for the usability
+ // of meta server so we're treading a bit of a fine line here.
+
+ if (chat_message.playern >= 0) {
+ return richtext_escape(chat_message.msg);
+ }
+
+ std::string sanitized;
+ for (std::string::size_type pos = 0; pos < chat_message.msg.size(); ++pos) {
+ if (chat_message.msg[pos] == '<') {
+ static const std::string good1 = "</p><p";
+ static const std::string good2 = "<br>";
+ if (!chat_message.msg.compare(pos, good1.size(), good1)) {
+ // TODO(MiroslavR): The logic here seems flawed.
+ std::string::size_type nextclose = chat_message.msg.find('>', pos + good1.size());
+ if
+ (nextclose != std::string::npos &&
+ (nextclose == pos + good1.size() || chat_message.msg[pos + good1.size()] == ' '))
+ {
+ sanitized += good1;
+ pos += good1.size() - 1;
+ continue;
+ }
+ } else if (!chat_message.msg.compare(pos, good2.size(), good2)) {
+ sanitized += good2;
+ pos += good2.size() - 1;
+ continue;
+ }
+
+ sanitized += "<";
+ } else {
+ sanitized += chat_message.msg[pos];
+ }
+ }
+ return sanitized;
+}
=== modified file 'src/wui/chat_msg_layout.h'
--- src/wui/chat_msg_layout.h 2015-03-01 09:21:20 +0000
+++ src/wui/chat_msg_layout.h 2016-03-30 08:43:17 +0000
@@ -30,4 +30,6 @@
// Formats 'chat_message' as richtext.
std::string format_as_richtext(const ChatMessage& chat_message);
+std::string sanitize_message(const ChatMessage & chat_message);
+
#endif // end of include guard: WL_WUI_CHAT_MSG_LAYOUT_H
Follow ups