bool check_names_legal(const config& dir) { BOOST_FOREACH(const config &path, dir.child_range("file")) { if (!addon_name_legal(path["name"])) return false; } BOOST_FOREACH(const config &path, dir.child_range("dir")) { if (!addon_name_legal(path["name"])) return false; if (!check_names_legal(path)) return false; } return true; }
bool check_names_legal(const config& dir) { const config::child_list& files = dir.get_children("file"); for(config::child_list::const_iterator i = files.begin(); i != files.end(); ++i) { if (!addon_name_legal((**i)["name"])) return false; } const config::child_list& dirs = dir.get_children("dir"); { for(config::child_list::const_iterator i = dirs.begin(); i != dirs.end(); ++i) { if (!addon_name_legal((**i)["name"])) return false; if (!check_names_legal(**i)) return false; } } return true; }
void server::handle_upload(const server::request& req) { const config& upload = req.cfg; LOG_CS << "uploading campaign '" << upload["name"] << "' from " << req.addr << ".\n"; config data = upload.child("data"); const std::string& name = upload["name"]; config *campaign = nullptr; bool passed_name_utf8_check = false; try { const std::string& lc_name = utf8::lowercase(name); passed_name_utf8_check = true; for(config& c : campaigns().child_range("campaign")) { if(utf8::lowercase(c["name"]) == lc_name) { campaign = &c; break; } } } catch(const utf8::invalid_utf8_exception&) { if(!passed_name_utf8_check) { LOG_CS << "Upload aborted - invalid_utf8_exception caught on handle_upload() check 1, " << "the add-on pbl info contains invalid UTF-8\n"; send_error("Add-on rejected: The add-on name contains an invalid UTF-8 sequence.", req.sock); } else { LOG_CS << "Upload aborted - invalid_utf8_exception caught on handle_upload() check 2, " << "the internal add-ons list contains invalid UTF-8\n"; send_error("Server error: The server add-ons list is damaged.", req.sock); } return; } if(read_only_) { LOG_CS << "Upload aborted - uploads not permitted in read-only mode.\n"; send_error("Add-on rejected: The server is currently in read-only mode.", req.sock); } else if(!data) { LOG_CS << "Upload aborted - no add-on data.\n"; send_error("Add-on rejected: No add-on data was supplied.", req.sock); } else if(!addon_name_legal(upload["name"])) { LOG_CS << "Upload aborted - invalid add-on name.\n"; send_error("Add-on rejected: The name of the add-on is invalid.", req.sock); } else if(is_text_markup_char(upload["name"].str()[0])) { LOG_CS << "Upload aborted - add-on name starts with an illegal formatting character.\n"; send_error("Add-on rejected: The name of the add-on starts with an illegal formatting character.", req.sock); } else if(upload["title"].empty()) { LOG_CS << "Upload aborted - no add-on title specified.\n"; send_error("Add-on rejected: You did not specify the title of the add-on in the pbl file!", req.sock); } else if(is_text_markup_char(upload["title"].str()[0])) { LOG_CS << "Upload aborted - add-on title starts with an illegal formatting character.\n"; send_error("Add-on rejected: The title of the add-on starts with an illegal formatting character.", req.sock); } else if(get_addon_type(upload["type"]) == ADDON_UNKNOWN) { LOG_CS << "Upload aborted - unknown add-on type specified.\n"; send_error("Add-on rejected: You did not specify a known type for the add-on in the pbl file! (See PblWML: wiki.wesnoth.org/PblWML)", req.sock); } else if(upload["author"].empty()) { LOG_CS << "Upload aborted - no add-on author specified.\n"; send_error("Add-on rejected: You did not specify the author(s) of the add-on in the pbl file!", req.sock); } else if(upload["version"].empty()) { LOG_CS << "Upload aborted - no add-on version specified.\n"; send_error("Add-on rejected: You did not specify the version of the add-on in the pbl file!", req.sock); } else if(upload["description"].empty()) { LOG_CS << "Upload aborted - no add-on description specified.\n"; send_error("Add-on rejected: You did not specify a description of the add-on in the pbl file!", req.sock); } else if(upload["email"].empty()) { LOG_CS << "Upload aborted - no add-on email specified.\n"; send_error("Add-on rejected: You did not specify your email address in the pbl file!", req.sock); } else if(!check_names_legal(data)) { LOG_CS << "Upload aborted - invalid file names in add-on data.\n"; send_error("Add-on rejected: The add-on contains an illegal file or directory name." " File or directory names may not contain whitespace or any of the following characters: '/ \\ : ~'", req.sock); } else if(campaign && !authenticate(*campaign, upload["passphrase"])) { LOG_CS << "Upload aborted - incorrect passphrase.\n"; send_error("Add-on rejected: The add-on already exists, and your passphrase was incorrect.", req.sock); } else { const time_t upload_ts = time(nullptr); LOG_CS << "Upload is owner upload.\n"; try { if(blacklist_.is_blacklisted(name, upload["title"].str(), upload["description"].str(), upload["author"].str(), req.addr, upload["email"].str())) { LOG_CS << "Upload denied - blacklisted add-on information.\n"; send_error("Add-on upload denied. Please contact the server administration for assistance.", req.sock); return; } } catch(const utf8::invalid_utf8_exception&) { LOG_CS << "Upload aborted - the add-on pbl info contains invalid UTF-8 and cannot be " << "checked against the blacklist\n"; send_error("Add-on rejected: The add-on publish information contains an invalid UTF-8 sequence.", req.sock); return; } const bool existing_upload = campaign != nullptr; std::string message = "Add-on accepted."; if(campaign == nullptr) { campaign = &campaigns().add_child("campaign"); (*campaign)["original_timestamp"] = upload_ts; } (*campaign)["title"] = upload["title"]; (*campaign)["name"] = upload["name"]; (*campaign)["filename"] = "data/" + upload["name"].str(); (*campaign)["author"] = upload["author"]; (*campaign)["description"] = upload["description"]; (*campaign)["version"] = upload["version"]; (*campaign)["icon"] = upload["icon"]; (*campaign)["translate"] = upload["translate"]; (*campaign)["dependencies"] = upload["dependencies"]; (*campaign)["upload_ip"] = req.addr; (*campaign)["type"] = upload["type"]; (*campaign)["email"] = upload["email"]; if(!existing_upload) { set_passphrase(*campaign, upload["passphrase"]); } if((*campaign)["downloads"].empty()) { (*campaign)["downloads"] = 0; } (*campaign)["timestamp"] = upload_ts; int uploads = (*campaign)["uploads"].to_int() + 1; (*campaign)["uploads"] = uploads; (*campaign).clear_children("feedback"); if(const config& url_params = upload.child("feedback")) { (*campaign).add_child("feedback", url_params); } const std::string& filename = (*campaign)["filename"].str(); data["title"] = (*campaign)["title"]; data["name"] = ""; data["campaign_name"] = (*campaign)["name"]; data["author"] = (*campaign)["author"]; data["description"] = (*campaign)["description"]; data["version"] = (*campaign)["version"]; data["timestamp"] = (*campaign)["timestamp"]; data["original_timestamp"] = (*campaign)["original_timestamp"]; data["icon"] = (*campaign)["icon"]; data["type"] = (*campaign)["type"]; (*campaign).clear_children("translation"); find_translations(data, *campaign); add_license(data); { filesystem::scoped_ostream campaign_file = filesystem::ostream_file(filename); config_writer writer(*campaign_file, true, compress_level_); writer.write(data); } (*campaign)["size"] = filesystem::file_size(filename); write_config(); send_message(message, req.sock); fire("hook_post_upload", upload["name"]); } }