ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

handlerutils.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "backends/networking/sdl_net/handlerutils.h"
00024 #include "backends/networking/sdl_net/localwebserver.h"
00025 #include "backends/saves/default/default-saves.h"
00026 #include "common/archive.h"
00027 #include "common/config-manager.h"
00028 #include "common/file.h"
00029 #include "common/translation.h"
00030 #include "common/unzip.h"
00031 #include "common/encoding.h"
00032 
00033 namespace Networking {
00034 
00035 #define ARCHIVE_NAME "wwwroot.zip"
00036 
00037 #define INDEX_PAGE_NAME ".index.html"
00038 
00039 Common::Archive *HandlerUtils::getZipArchive() {
00040     // first search in themepath
00041     if (ConfMan.hasKey("themepath")) {
00042         const Common::FSNode &node = Common::FSNode(ConfMan.get("themepath"));
00043         if (node.exists() && node.isReadable() && node.isDirectory()) {
00044             Common::FSNode fileNode = node.getChild(ARCHIVE_NAME);
00045             if (fileNode.exists() && fileNode.isReadable() && !fileNode.isDirectory()) {
00046                 Common::SeekableReadStream *const stream = fileNode.createReadStream();
00047                 Common::Archive *zipArchive = Common::makeZipArchive(stream);
00048                 if (zipArchive)
00049                     return zipArchive;
00050             }
00051         }
00052     }
00053 
00054     // then use SearchMan to find it
00055     Common::ArchiveMemberList fileList;
00056     SearchMan.listMatchingMembers(fileList, ARCHIVE_NAME);
00057     for (Common::ArchiveMemberList::iterator it = fileList.begin(); it != fileList.end(); ++it) {
00058         Common::ArchiveMember       const &m = **it;
00059         Common::SeekableReadStream *const stream = m.createReadStream();
00060         Common::Archive *zipArchive = Common::makeZipArchive(stream);
00061         if (zipArchive)
00062             return zipArchive;
00063     }
00064 
00065     return nullptr;
00066 }
00067 
00068 Common::ArchiveMemberList HandlerUtils::listArchive() {
00069     Common::ArchiveMemberList resultList;
00070     Common::Archive *zipArchive = getZipArchive();
00071     if (zipArchive) {
00072         zipArchive->listMembers(resultList);
00073         delete zipArchive;
00074     }
00075     return resultList;
00076 }
00077 
00078 Common::SeekableReadStream *HandlerUtils::getArchiveFile(Common::String name) {
00079     Common::SeekableReadStream *result = nullptr;
00080     Common::Archive *zipArchive = getZipArchive();
00081     if (zipArchive) {
00082         const Common::ArchiveMemberPtr ptr = zipArchive->getMember(name);
00083         if (ptr.get() == nullptr)
00084             return nullptr;
00085         result = ptr->createReadStream();
00086         delete zipArchive;
00087     }
00088     return result;
00089 }
00090 
00091 Common::String HandlerUtils::readEverythingFromStream(Common::SeekableReadStream *const stream) {
00092     Common::String result;
00093     char buf[1024];
00094     uint32 readBytes;
00095     while (!stream->eos()) {
00096         readBytes = stream->read(buf, 1024);
00097         result += Common::String(buf, readBytes);
00098     }
00099     return result;
00100 }
00101 
00102 Common::String HandlerUtils::normalizePath(const Common::String &path) {
00103     Common::String normalized;
00104     bool slash = false;
00105     for (uint32 i = 0; i < path.size(); ++i) {
00106         char c = path[i];
00107         if (c == '\\' || c == '/') {
00108             slash = true;
00109             continue;
00110         }
00111 
00112         if (slash) {
00113             normalized += '/';
00114             slash = false;
00115         }
00116 
00117         if ('A' <= c && c <= 'Z') {
00118             normalized += c - 'A' + 'a';
00119         } else {
00120             normalized += c;
00121         }
00122     }
00123     if (slash) normalized += '/';
00124     return normalized;
00125 }
00126 
00127 bool HandlerUtils::hasForbiddenCombinations(const Common::String &path) {
00128     return (path.contains("/../") || path.contains("\\..\\") || path.contains("\\../") || path.contains("/..\\"));
00129 }
00130 
00131 bool HandlerUtils::isBlacklisted(const Common::String &path) {
00132     const char *blacklist[] = {
00133         "/etc",
00134         "/bin",
00135         "c:/windows" // just saying: I know guys who install windows on another drives
00136     };
00137 
00138     // normalize path
00139     Common::String normalized = normalizePath(path);
00140 
00141     uint32 size = sizeof(blacklist) / sizeof(const char *);
00142     for (uint32 i = 0; i < size; ++i)
00143         if (normalized.hasPrefix(blacklist[i]))
00144             return true;
00145 
00146     return false;
00147 }
00148 
00149 bool HandlerUtils::hasPermittedPrefix(const Common::String &path) {
00150     // normalize path
00151     Common::String normalized = normalizePath(path);
00152 
00153     // prefix for /root/
00154     Common::String prefix;
00155     if (ConfMan.hasKey("rootpath", "cloud")) {
00156         prefix = normalizePath(ConfMan.get("rootpath", "cloud"));
00157         if (prefix == "/" || normalized.hasPrefix(prefix))
00158             return true;
00159     }
00160 
00161     // prefix for /saves/
00162 #ifdef USE_LIBCURL
00163     DefaultSaveFileManager *manager = dynamic_cast<DefaultSaveFileManager *>(g_system->getSavefileManager());
00164     prefix = (manager ? manager->concatWithSavesPath("") : ConfMan.get("savepath"));
00165 #else
00166     prefix = ConfMan.get("savepath");
00167 #endif
00168     return (normalized.hasPrefix(normalizePath(prefix)));
00169 }
00170 
00171 bool HandlerUtils::permittedPath(const Common::String path) {
00172     return hasPermittedPrefix(path) && !isBlacklisted(path);
00173 }
00174 
00175 Common::String HandlerUtils::toUtf8(const char *text) {
00176 #ifdef USE_TRANSLATION
00177     Common::String guiEncoding = TransMan.getCurrentCharset();
00178     if (guiEncoding != "ASCII") {
00179         char *utf8Text = Common::Encoding::convert("utf-8", guiEncoding, text, strlen(text));
00180         if (utf8Text != nullptr) {
00181             Common::String str(utf8Text);
00182             free(utf8Text);
00183             return str;
00184         }
00185     }
00186 #endif
00187     return Common::String(text);
00188 }
00189 
00190 void HandlerUtils::setMessageHandler(Client &client, Common::String message, Common::String redirectTo) {
00191     Common::String response = "<html><head><title>ResidualVM</title><meta charset=\"utf-8\"/></head><body>{message}</body></html>";
00192 
00193     // load stylish response page from the archive
00194     Common::SeekableReadStream *const stream = getArchiveFile(INDEX_PAGE_NAME);
00195     if (stream)
00196         response = readEverythingFromStream(stream);
00197 
00198     replace(response, "{message}", message);
00199     if (redirectTo.empty())
00200         LocalWebserver::setClientGetHandler(client, response);
00201     else
00202         LocalWebserver::setClientRedirectHandler(client, response, redirectTo);
00203 }
00204 
00205 void HandlerUtils::setFilesManagerErrorMessageHandler(Client &client, Common::String message, Common::String redirectTo) {
00206     setMessageHandler(
00207         client,
00208         Common::String::format(
00209             "%s<br/><a href=\"files%s?path=%s\">%s</a>",
00210             message.c_str(),
00211             client.queryParameter("ajax") == "true" ? "AJAX" : "",
00212             "%2F", //that's encoded "/"
00213             toUtf8(_("Back to the files manager")).c_str()
00214         ),
00215         redirectTo
00216     );
00217 }
00218 
00219 } // End of namespace Networking


Generated on Sat Jun 27 2020 05:00:31 for ResidualVM by doxygen 1.7.1
curved edge   curved edge