Merge lp:~widelands-dev/widelands/bug-1588063 into lp:widelands

Proposed by Tino
Status: Merged
Merged at revision: 8051
Proposed branch: lp:~widelands-dev/widelands/bug-1588063
Merge into: lp:widelands
Diff against target: 182 lines (+48/-12)
7 files modified
src/editor/ui_menus/main_menu_save_map.cc (+9/-3)
src/editor/ui_menus/main_menu_save_map_make_directory.cc (+3/-1)
src/io/filesystem/disk_filesystem.cc (+14/-6)
src/io/filesystem/layered_filesystem.cc (+15/-0)
src/io/filesystem/layered_filesystem.h (+2/-0)
src/logic/save_handler.cc (+3/-1)
src/wui/game_main_menu_save_game.cc (+2/-1)
To merge this branch: bzr merge lp:~widelands-dev/widelands/bug-1588063
Reviewer Review Type Date Requested Status
Tino Approve
GunChleoc Needs Resubmitting
Klaus Halfmann compile, review, test Approve
Review via email: mp+301636@code.launchpad.net

Commit message

Fix automatic creation of the maps/My_Maps folder in Windows. Prevent the user from entering illegal filenames.

Description of the change

Use system dependant file seperator for the My_Maps subdirectory.
Now ensure_directory_exists() does work also on win32.

I don't like the #ifdef __win32 solution, but i was not able to FileSystem::file_separator() because i lack c++ knowledge to concatenate char/char*/char[].

Suggestions welcome.

To post a comment you must log in.
Revision history for this message
GunChleoc (gunchleoc) wrote :

Ah, bl*** file separators, my bad.

I will look into concatenating this properly.

Revision history for this message
Tino (tino79) wrote :

Found another bug in the current state of implementation: https://bugs.launchpad.net/widelands/+bug/1608558

review: Needs Fixing
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1222. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/148893466.
Appveyor build 1064. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1588063-1064.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1222. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/148893466.
Appveyor build 1064. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1588063-1064.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Bunnybot encountered an error while working on this merge proposal:

The read operation timed out

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1222. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/148893466.
Appveyor build 1064. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1588063-1064.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Bunnybot encountered an error while working on this merge proposal:

<urlopen error timed out>

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1222. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/148893466.
Appveyor build 1064. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1588063-1064.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1229. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/149710458.
Appveyor build 1071. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1588063-1071.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1229. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/149710458.
Appveyor build 1071. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1588063-1071.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Bunnybot encountered an error while working on this merge proposal:

The read operation timed out

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1231. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/149798427.
Appveyor build 1073. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1588063-1073.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

Testing on OSX:

* removed .widelands folder
* :bug-1588063$ ./widelands --editor
* Created some random map and saved it
* found ./widelands/maps/My_Maps, OK
* Copied some selfmade map into ./widelands/maps
ls -R maps
Crossriver.wmf My_Maps

maps/My_Maps:
Test1608558.wmf

* I can open Crossriver.wmf in the Editor, is merged into the list of Maps.

I now will restore my old .widelands folder an try some evil characters

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1236. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/149854580.
Appveyor build 1078. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1588063-1078.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

OK, Tested some "evil" charaters. On OSX '`´&$()[]{} are allowed while |/":* are not (incomplete).

Maybe we should filter these as well, to avoid Filenames with bad effects on the Commandline?
OTOH the average user will not not use such characters, will he/she?

Code LGTM, but I can test OSX only, so we need some Windows test, too.

review: Approve (compile, review, test)
Revision history for this message
GunChleoc (gunchleoc) wrote :

I have decided to only filter out the characters that can lead to potential crashes, not the "inconvenient" ones that look confusing on the command line (like e.g. $).

I have tested on Windows and all should be fine now - both bugs fixed.

review: Needs Resubmitting
Revision history for this message
Tino (tino79) wrote :

Nice, thanks Gun.

I can compile fine and do not find those bugs active any longer.

@bunnybot merge

review: Approve
Revision history for this message
GunChleoc (gunchleoc) wrote :

*happy* Thanks for testing, everyone!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/editor/ui_menus/main_menu_save_map.cc'
2--- src/editor/ui_menus/main_menu_save_map.cc 2016-08-04 15:49:05 +0000
3+++ src/editor/ui_menus/main_menu_save_map.cc 2016-08-04 19:19:13 +0000
4@@ -155,8 +155,10 @@
5 MainMenuSaveMapMakeDirectory md(this, _("unnamed"));
6 if (md.run<UI::Panel::Returncodes>() == UI::Panel::Returncodes::kOk) {
7 g_fs->ensure_directory_exists(curdir_);
8- // create directory
9+ // Create directory.
10 std::string fullname = curdir_ + g_fs->file_separator() + md.get_dirname();
11+ // Trim it for preceding/trailing whitespaces in user input
12+ boost::trim(fullname);
13 g_fs->make_directory(fullname);
14 fill_table();
15 }
16@@ -215,7 +217,8 @@
17 * The editbox was changed. Enable ok button
18 */
19 void MainMenuSaveMap::edit_box_changed() {
20- ok_.set_enabled(!editbox_->text().empty());
21+ // Prevent the user from creating nonsense file names, like e.g. ".." or "...".
22+ ok_.set_enabled(LayeredFileSystem::is_legal_filename(editbox_->text()));
23 }
24
25 void MainMenuSaveMap::set_current_directory(const std::string& filename) {
26@@ -237,11 +240,14 @@
27 // Make sure that the current directory exists and is writeable.
28 g_fs->ensure_directory_exists(curdir_);
29
30+ // Trim it for preceding/trailing whitespaces in user input
31+ boost::trim(filename);
32+
33 // OK, first check if the extension matches (ignoring case).
34 if (!boost::iends_with(filename, WLMF_SUFFIX))
35 filename += WLMF_SUFFIX;
36
37- // append directory name
38+ // Append directory name.
39 const std::string complete_filename = curdir_ + g_fs->file_separator() + filename;
40
41 // Check if file exists. If so, show a warning.
42
43=== modified file 'src/editor/ui_menus/main_menu_save_map_make_directory.cc'
44--- src/editor/ui_menus/main_menu_save_map_make_directory.cc 2016-08-04 15:49:05 +0000
45+++ src/editor/ui_menus/main_menu_save_map_make_directory.cc 2016-08-04 19:19:13 +0000
46@@ -22,6 +22,7 @@
47 #include "base/i18n.h"
48 #include "graphic/font_handler1.h"
49 #include "graphic/graphic.h"
50+#include "io/filesystem/layered_filesystem.h"
51
52 MainMenuSaveMapMakeDirectory::MainMenuSaveMapMakeDirectory(UI::Panel* const parent,
53 char const* dirname)
54@@ -91,6 +92,7 @@
55 */
56 void MainMenuSaveMapMakeDirectory::edit_changed() {
57 const std::string& text = edit_.text();
58- ok_button_.set_enabled(!text.empty());
59+ // Prevent the user from creating nonsense directory names, like e.g. ".." or "...".
60+ ok_button_.set_enabled(LayeredFileSystem::is_legal_filename(text));
61 dirname_ = text;
62 }
63
64=== modified file 'src/io/filesystem/disk_filesystem.cc'
65--- src/io/filesystem/disk_filesystem.cc 2016-08-04 15:49:05 +0000
66+++ src/io/filesystem/disk_filesystem.cc 2016-08-04 19:19:13 +0000
67@@ -297,17 +297,25 @@
68 * if the dir can't be created or if a file with this name exists
69 */
70 void RealFSImpl::ensure_directory_exists(const std::string& dirname) {
71+ std::string clean_dirname = dirname;
72+#ifdef _WIN32
73+ // Make sure we always use "/" for splitting the directory, because
74+ // directory names might be hardcoded in C++ or come from the file system.
75+ // Calling canonicalize_name will take care of this working for all file systems.
76+ boost::replace_all(clean_dirname, "\\", "/");
77+#endif
78+
79 try {
80 std::string::size_type it = 0;
81- while (it < dirname.size()) {
82- it = dirname.find(file_separator(), it);
83+ while (it < clean_dirname.size()) {
84+ it = clean_dirname.find('/', it);
85
86- FileSystemPath fspath(canonicalize_name(dirname.substr(0, it)));
87+ FileSystemPath fspath(canonicalize_name(clean_dirname.substr(0, it)));
88 if (fspath.exists_ && !fspath.is_directory_)
89 throw wexception("'%s' in directory '%s' exists and is not a directory",
90- dirname.substr(0, it).c_str(), directory_.c_str());
91+ clean_dirname.substr(0, it).c_str(), directory_.c_str());
92 if (!fspath.exists_)
93- make_directory(dirname.substr(0, it));
94+ make_directory(clean_dirname.substr(0, it));
95
96 if (it == std::string::npos)
97 break;
98@@ -315,7 +323,7 @@
99 }
100 } catch (const std::exception& e) {
101 throw wexception("RealFSImpl::ensure_directory_exists(%s) in directory '%s': %s",
102- dirname.c_str(), directory_.c_str(), e.what());
103+ clean_dirname.c_str(), directory_.c_str(), e.what());
104 }
105 }
106
107
108=== modified file 'src/io/filesystem/layered_filesystem.cc'
109--- src/io/filesystem/layered_filesystem.cc 2016-08-04 15:49:05 +0000
110+++ src/io/filesystem/layered_filesystem.cc 2016-08-04 19:19:13 +0000
111@@ -22,6 +22,9 @@
112 #include <cstdio>
113 #include <memory>
114
115+#include <boost/algorithm/string/predicate.hpp>
116+#include <boost/regex.hpp>
117+
118 #include "base/log.h"
119 #include "base/wexception.h"
120 #include "io/fileread.h"
121@@ -38,6 +41,18 @@
122 LayeredFileSystem::~LayeredFileSystem() {
123 }
124
125+bool LayeredFileSystem::is_legal_filename(const std::string& filename) {
126+ // No potential file separators or other potentially illegal characters
127+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
128+ // http://www.linfo.org/file_name.html
129+ // https://support.apple.com/en-us/HT202808
130+ // We can't just regex for word & digit characters here because of non-Latin scripts.
131+ boost::regex re(".*[<>:\"|?*/\\\\].*");
132+ return !filename.empty() && !boost::starts_with(filename, ".") &&
133+ !boost::starts_with(filename, " ") && !boost::starts_with(filename, "-") &&
134+ !boost::regex_match(filename, re);
135+}
136+
137 /**
138 * Just assume that at least one of our child FSs is writable
139 */
140
141=== modified file 'src/io/filesystem/layered_filesystem.h'
142--- src/io/filesystem/layered_filesystem.h 2016-08-04 15:49:05 +0000
143+++ src/io/filesystem/layered_filesystem.h 2016-08-04 19:19:13 +0000
144@@ -60,6 +60,8 @@
145
146 std::set<std::string> list_directory(const std::string& path) override;
147
148+ /// Returns true if the filename is legal in all operating systems
149+ static bool is_legal_filename(const std::string& filename);
150 bool is_writable() const override;
151 bool file_exists(const std::string& path) override;
152 bool is_directory(const std::string& path) override;
153
154=== modified file 'src/logic/save_handler.cc'
155--- src/logic/save_handler.cc 2016-08-04 15:49:05 +0000
156+++ src/logic/save_handler.cc 2016-08-04 19:19:13 +0000
157@@ -174,8 +174,10 @@
158 */
159 std::string SaveHandler::create_file_name(const std::string& dir,
160 const std::string& filename) const {
161- // Append directory name
162+ // Append directory name.
163 std::string complete_filename = dir + g_fs->file_separator() + filename;
164+ // Trim it for preceding/trailing whitespaces in user input
165+ boost::trim(complete_filename);
166
167 // Now check if the extension matches (ignoring case)
168 if (!boost::iends_with(filename, WLGF_SUFFIX)) {
169
170=== modified file 'src/wui/game_main_menu_save_game.cc'
171--- src/wui/game_main_menu_save_game.cc 2016-08-04 15:49:05 +0000
172+++ src/wui/game_main_menu_save_game.cc 2016-08-04 19:19:13 +0000
173@@ -207,7 +207,8 @@
174 * The editbox was changed. Enable ok button
175 */
176 void GameMainMenuSaveGame::edit_box_changed() {
177- button_ok_->set_enabled(editbox_.text().size());
178+ // Prevent the user from creating nonsense directory names, like e.g. ".." or "...".
179+ button_ok_->set_enabled(LayeredFileSystem::is_legal_filename(editbox_.text()));
180 }
181
182 static void dosave(InteractiveGameBase& igbase, const std::string& complete_filename) {

Subscribers

People subscribed via source and target branches

to status/vote changes: