]> git.openstreetmap.org Git - rails.git/commitdiff
Enforce rate limit for API calls which make changes
authorTom Hughes <tom@compton.nu>
Sun, 29 Oct 2023 16:11:23 +0000 (16:11 +0000)
committerTom Hughes <tom@compton.nu>
Thu, 2 Nov 2023 08:59:57 +0000 (08:59 +0000)
app/controllers/api/changesets_controller.rb
app/controllers/api/nodes_controller.rb
app/controllers/api/relations_controller.rb
app/controllers/api/ways_controller.rb
app/controllers/api_controller.rb
test/controllers/api/changesets_controller_test.rb

index 7bb7a5a4de14bddb49f988f7f9285d96de074b1e..9bdf0f2bd3b075a5a5eb09e5755bfa76ee224bde 100644 (file)
@@ -92,6 +92,10 @@ module Api
       diff_reader = DiffReader.new(request.raw_post, changeset)
       Changeset.transaction do
         result = diff_reader.commit
+        # the number of changes in this changeset has already been
+        # updated and is visible in this transaction so we don't need
+        # to allow for any more when checking the limit
+        check_rate_limit(0)
         render :xml => result.to_s
       end
     end
index 6934a13c04b9d6e8373a0b68bfde994a9f71177d..fb808828c80a221d794b205cd256d28f34b7af7c 100644 (file)
@@ -14,6 +14,7 @@ module Api
     around_action :api_call_handle_error, :api_call_timeout
 
     before_action :set_request_formats, :except => [:create, :update, :delete]
+    before_action :check_rate_limit, :only => [:create, :update, :delete]
 
     # Dump the details on many nodes whose ids are given in the "nodes" parameter.
     def index
index 19aed6a85db00dd715c7fe05ee9662eca08db20d..e833ae8307bc48bb8898cafde4cf2bf9d3c1df63 100644 (file)
@@ -12,6 +12,7 @@ module Api
     around_action :api_call_handle_error, :api_call_timeout
 
     before_action :set_request_formats, :except => [:create, :update, :delete]
+    before_action :check_rate_limit, :only => [:create, :update, :delete]
 
     def index
       raise OSM::APIBadUserInput, "The parameter relations is required, and must be of the form relations=id[,id[,id...]]" unless params["relations"]
index c4fce48d07d7badcfa86f797336ee05ed3099416..5e72cfe209db66c29e5666bc2af744722acc40b6 100644 (file)
@@ -12,6 +12,7 @@ module Api
     around_action :api_call_handle_error, :api_call_timeout
 
     before_action :set_request_formats, :except => [:create, :update, :delete]
+    before_action :check_rate_limit, :only => [:create, :update, :delete]
 
     def index
       raise OSM::APIBadUserInput, "The parameter ways is required, and must be of the form ways=id[,id[,id...]]" unless params["ways"]
index 89388c0bbf044db798f9c2f2258a61ca1cd25258..7e1b06a8dd3bbde8f7cc6c7bbc538e205e65937d 100644 (file)
@@ -192,4 +192,14 @@ class ApiController < ApplicationController
     ActiveRecord::Base.connection.raw_connection.cancel
     raise OSM::APITimeoutError
   end
+
+  ##
+  # check the api change rate limit
+  def check_rate_limit(new_changes = 1)
+    max_changes = ActiveRecord::Base.connection.select_value(
+      "SELECT api_rate_limit($1)", "api_rate_limit", [current_user.id]
+    )
+
+    raise OSM::APIRateLimitExceeded if new_changes > max_changes
+  end
 end
index 802e006e1190e025d898d120d6964b81a817d384..8e4ba6ed412bb5f218ba81fd34b188bd7646a578 100644 (file)
@@ -2183,7 +2183,11 @@ module Api
     # check that a changeset can contain a certain max number of changes.
     ## FIXME should be changed to an integration test due to the with_controller
     def test_changeset_limits
-      auth_header = basic_authorization_header create(:user).email, "test"
+      user = create(:user)
+      auth_header = basic_authorization_header user.email, "test"
+
+      # create an old changeset to ensure we have the maximum rate limit
+      create(:changeset, :user => user, :created_at => Time.now.utc - 28.days)
 
       # open a new changeset
       xml = "<osm><changeset/></osm>"