Skip to content

Commit

Permalink
Add the ability to limit changeset size
Browse files Browse the repository at this point in the history
  • Loading branch information
mmd-osm committed Jun 19, 2024
1 parent 467a61d commit 53b3989
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 0 deletions.
2 changes: 2 additions & 0 deletions include/cgimap/backend/apidb/pgsql_update.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class pgsql_update : public data_update {

uint32_t get_rate_limit(osm_user_id_t uid) override;

uint64_t get_bbox_size_limit(osm_user_id_t uid) override;

/**
* abstracts the creation of transactions for the
* data updates.
Expand Down
3 changes: 3 additions & 0 deletions include/cgimap/data_update.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ class data_update {
// get the current rate limit for changeset uploads for a given user id
virtual uint32_t get_rate_limit(osm_user_id_t) = 0;

// get the current maximum bounding box size for a given user id
virtual uint64_t get_bbox_size_limit(osm_user_id_t uid) = 0;

/**
* factory for the creation of data updates. this abstracts away
* the creation process of transactions, and allows some up-front
Expand Down
14 changes: 14 additions & 0 deletions include/cgimap/options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class global_settings_base {
virtual uint32_t get_ratelimiter_ratelimit(bool) const = 0;
virtual uint32_t get_ratelimiter_maxdebt(bool) const = 0;
virtual bool get_ratelimiter_upload() const = 0;
virtual bool get_bbox_size_limiter_upload() const = 0;
};

class global_settings_default : public global_settings_base {
Expand Down Expand Up @@ -97,6 +98,10 @@ class global_settings_default : public global_settings_base {
bool get_ratelimiter_upload() const override {
return false;
}

bool get_bbox_size_limiter_upload() const override {
return false;
}
};

class global_settings_via_options : public global_settings_base {
Expand Down Expand Up @@ -175,6 +180,10 @@ class global_settings_via_options : public global_settings_base {
return m_ratelimiter_upload;
}

bool get_bbox_size_limiter_upload() const override {
return m_bbox_size_limiter_upload;
}

private:
void init_fallback_values(const global_settings_base &def);
void set_new_options(const po::variables_map &options);
Expand All @@ -191,6 +200,7 @@ class global_settings_via_options : public global_settings_base {
void set_ratelimiter_ratelimit(const po::variables_map &options);
void set_ratelimiter_maxdebt(const po::variables_map &options);
void set_ratelimiter_upload(const po::variables_map &options);
void set_bbox_size_limiter_upload(const po::variables_map &options);
bool validate_timeout(const std::string &timeout) const;

uint32_t m_payload_max_size;
Expand All @@ -208,6 +218,7 @@ class global_settings_via_options : public global_settings_base {
uint32_t m_ratelimiter_maxdebt;
uint32_t m_moderator_ratelimiter_maxdebt;
bool m_ratelimiter_upload;
bool m_bbox_size_limiter_upload;
};

class global_settings final {
Expand Down Expand Up @@ -256,6 +267,9 @@ class global_settings final {
// Use ratelimiter for changeset uploads
static bool get_ratelimiter_upload() { return settings->get_ratelimiter_upload(); }

// Use bbox size limiter for changeset uploads
static bool get_bbox_size_limiter_upload() { return settings->get_bbox_size_limiter_upload(); }

private:
static std::unique_ptr<global_settings_base> settings; // gets initialized with global_settings_default instance
};
Expand Down
4 changes: 4 additions & 0 deletions include/cgimap/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ class bbox_t {
os << "[" << bbox.minlat << "," << bbox.minlon << "," << bbox.maxlat << "," << bbox.maxlon << "]";
return os;
}

long linear_size() const {
return ((maxlon - minlon) + (maxlat - minlat));
}
};

#endif
Expand Down
20 changes: 20 additions & 0 deletions src/api06/changeset_upload_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,26 @@ changeset_upload_responder::changeset_upload_responder(mime::type mt,
}
}

if (global_settings::get_bbox_size_limiter_upload()) {

auto const cs_bbox = handler.get_bbox();

if (!(cs_bbox == bbox_t())) // valid bbox?
{
auto const max_bbox_size = upd.get_bbox_size_limit(*user_id);

if (cs_bbox.linear_size() > max_bbox_size) {

logger::message(
fmt::format(
"Upload of {} changes by user {} in changeset {} blocked due to bbox size limit exceeded, max bbox size {}",
new_changes, *user_id, changeset, max_bbox_size));

throw http::payload_too_large("Upload has been blocked, since it exceeds the current bbox size limit.");
}
}
}

changeset_updater->update_changeset(new_changes, handler.get_bbox());

upd.commit();
Expand Down
19 changes: 19 additions & 0 deletions src/backend/apidb/pgsql_update.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,25 @@ uint32_t pgsql_update::get_rate_limit(osm_user_id_t uid)
return std::max(0, rate_limit);
}

uint64_t pgsql_update::get_bbox_size_limit(osm_user_id_t uid)
{
{
m.prepare("api_size_limit",
R"(SELECT * FROM api_size_limit($1) LIMIT 1 )");

auto res = m.exec_prepared("api_size_limit", uid);

if (res.size() != 1) {
throw http::server_error("api_size_limit db function did not return any data");
}

auto row = res[0];
auto bbox_size_limit = row[0].as<int64_t>();

return std::max(bbox_size_limit, 0l);
}
}


pgsql_update::factory::factory(const po::variables_map &opts)
: m_connection(connect_db_str(opts)),
Expand Down
1 change: 1 addition & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ void get_options(int argc, char **argv, po::variables_map &options) {
("max-relation-members", po::value<int>(), "max number of relation members per relation")
("max-element-tags", po::value<int>(), "max number of tags per OSM element")
("ratelimit-upload", po::value<bool>(), "enable rate limiting for changeset upload")
("bbox-size-limit-upload", po::value<bool>(), "enable bbox size limit for changeset upload")
;
// clang-format on

Expand Down
7 changes: 7 additions & 0 deletions src/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ void global_settings_via_options::init_fallback_values(const global_settings_bas
m_ratelimiter_maxdebt = def.get_ratelimiter_maxdebt(false);
m_moderator_ratelimiter_maxdebt = def.get_ratelimiter_maxdebt(true);
m_ratelimiter_upload = def.get_ratelimiter_upload();
m_bbox_size_limiter_upload = def.get_bbox_size_limiter_upload();
}

void global_settings_via_options::set_new_options(const po::variables_map &options) {
Expand All @@ -50,6 +51,7 @@ void global_settings_via_options::set_new_options(const po::variables_map &optio
set_ratelimiter_ratelimit(options);
set_ratelimiter_maxdebt(options);
set_ratelimiter_upload(options);
set_bbox_size_limiter_upload(options);
}

void global_settings_via_options::set_payload_max_size(const po::variables_map &options) {
Expand Down Expand Up @@ -185,6 +187,11 @@ void global_settings_via_options::set_ratelimiter_upload(const po::variables_map
}
}

void global_settings_via_options::set_bbox_size_limiter_upload(const po::variables_map &options) {
if (options.count("bbox-size-limit-upload")) {
m_bbox_size_limiter_upload = options["bbox-size-limit-upload"].as<bool>();
}
}

bool global_settings_via_options::validate_timeout(const std::string &timeout) const {
std::smatch sm;
Expand Down

0 comments on commit 53b3989

Please sign in to comment.