Validate _server.pbl files on upload against the schema (#7239)

This commit is contained in:
Celtic Minstrel 2023-01-25 19:10:40 -05:00 committed by GitHub
parent 77baa1efc7
commit 9fcfb04bde
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 36 additions and 16 deletions

View file

@ -274,7 +274,8 @@ bool addons_client::delete_remote_addon(const std::string& id, std::string& resp
{
response_message.clear();
config cfg = get_addon_pbl_info(id);
// No point in validating when we're deleting it.
config cfg = get_addon_pbl_info(id, false);
utils::string_map i18n_symbols;
i18n_symbols["addon_title"] = font::escape_text(cfg["title"]);

View file

@ -19,7 +19,9 @@
#include "filesystem.hpp"
#include "log.hpp"
#include "serialization/parser.hpp"
#include "serialization/schema_validator.hpp"
#include "game_version.hpp"
#include "wml_exception.hpp"
#include <boost/algorithm/string.hpp>
@ -65,15 +67,26 @@ bool have_addon_pbl_info(const std::string& addon_name)
return filesystem::file_exists(get_pbl_file_path(addon_name));
}
config get_addon_pbl_info(const std::string& addon_name)
config get_addon_pbl_info(const std::string& addon_name, bool do_validate)
{
config cfg;
const std::string& pbl_path = get_pbl_file_path(addon_name);
try {
filesystem::scoped_istream stream = filesystem::istream_file(pbl_path);
read(cfg, *stream);
std::unique_ptr<schema_validation::schema_validator> validator;
if(do_validate) {
validator = std::make_unique<schema_validation::schema_validator>(filesystem::get_wml_location("schema/pbl.cfg"));
validator->set_create_exceptions(true);
}
read(cfg, *stream, validator.get());
} catch(const config::error& e) {
throw invalid_pbl_exception(pbl_path, e.message);
} catch(wml_exception& e) {
auto msg = e.user_message;
e.user_message += " in " + addon_name;
boost::replace_all(e.dev_message, "<unknown>", filesystem::sanitize_path(pbl_path));
e.show();
throw invalid_pbl_exception(pbl_path, msg);
}
return cfg;
@ -187,7 +200,8 @@ std::map<std::string, std::string> installed_addons_and_versions()
for(const std::string& addon_id : installed_addons()) {
if(have_addon_pbl_info(addon_id)) {
try {
addons[addon_id] = get_addon_pbl_info(addon_id)["version"].str();
// Just grabbing the version, so don't bother validating the pbl
addons[addon_id] = get_addon_pbl_info(addon_id, false)["version"].str();
} catch(const invalid_pbl_exception&) {
addons[addon_id] = "Invalid pbl file, version unknown";
}

View file

@ -100,11 +100,12 @@ bool have_addon_in_vcs_tree(const std::string& addon_name);
* Gets the publish information for an add-on.
*
* @param addon_name The add-on's main directory/file name.
* @param do_validate Whether we want to run validation on the .pbl file.
*
* @exception invalid_pbl_exception If it is not possible to read the .pbl file
* (often due to invalid WML).
*/
config get_addon_pbl_info(const std::string& addon_name);
config get_addon_pbl_info(const std::string& addon_name, bool do_validate);
/**
* Sets the publish information for an add-on.

View file

@ -40,7 +40,8 @@ addon_tracking_info get_addon_tracking_info(const addon_info& addon)
t.remote_version = *addon.versions.begin();
// Try to obtain the version number from the .pbl first.
config pbl = get_addon_pbl_info(id);
// Just grabbing the version, no need to validate.
config pbl = get_addon_pbl_info(id, false);
if(pbl.has_attribute("version")) {
t.installed_version = pbl["version"].str();

View file

@ -456,7 +456,7 @@ void game_config_manager::load_addons_cfg()
if(have_addon_pbl_info(addon_id)) {
// Publishing info needs to be read from disk.
try {
metadata = get_addon_pbl_info(addon_id);
metadata = get_addon_pbl_info(addon_id, false);
} catch(const invalid_pbl_exception& e) {
const std::string log_msg = formatter()
<< "The provided addon has an invalid pbl file"

View file

@ -568,16 +568,18 @@ void addon_manager::load_addon_list()
// to match add-ons in the config list. It also fills in addon_info's id field. It's also
// neccessay to set local_only here so that flag can be properly set after addons_ is cleared
// and recreated by read_addons_list.
config pbl_cfg = get_addon_pbl_info(id);
pbl_cfg["name"] = id;
pbl_cfg["local_only"] = true;
try {
config pbl_cfg = get_addon_pbl_info(id, false);
pbl_cfg["name"] = id;
pbl_cfg["local_only"] = true;
// Add the add-on to the list.
addon_info addon(pbl_cfg);
addons_[id] = addon;
// Add the add-on to the list.
addon_info addon(pbl_cfg);
addons_[id] = addon;
// Add the addon to the config entry
cfg_.add_child("campaign", std::move(pbl_cfg));
// Add the addon to the config entry
cfg_.add_child("campaign", std::move(pbl_cfg));
} catch(invalid_pbl_exception&) {}
}
}
@ -907,7 +909,8 @@ void addon_manager::publish_addon(const addon_info& addon)
std::string server_msg;
const std::string addon_id = addon.id;
config cfg = get_addon_pbl_info(addon_id);
// Since the user is planning to upload an addon, this is the right time to validate the .pbl.
config cfg = get_addon_pbl_info(addon_id, true);
const version_info& version_to_publish = cfg["version"].str();