Commit 2a240bbb authored by Josianne Hyson's avatar Josianne Hyson Committed by Mayra Cabrera

Change project export rate limit to be user scoped

Scope the project export rate limit to user, rather than user and
project so that the limit is applied across all projects that the user
attempts to export.

For more information see:
https://gitlab.com/gitlab-org/gitlab/-/issues/212707

MR: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31719
parent ca34500c
......@@ -483,11 +483,12 @@ class ProjectsController < Projects::ApplicationController
def export_rate_limit
prefixed_action = "project_#{params[:action]}".to_sym
if rate_limiter.throttled?(prefixed_action, scope: [current_user, prefixed_action, @project])
project_scope = params[:action] == :download_export ? @project : nil
if rate_limiter.throttled?(prefixed_action, scope: [current_user, prefixed_action, project_scope].compact)
rate_limiter.log_request(request, "#{prefixed_action}_request_limit".to_sym, current_user)
flash[:alert] = _('This endpoint has been requested too many times. Try again later.')
redirect_to edit_project_path(@project)
render plain: _('This endpoint has been requested too many times. Try again later.'), status: :too_many_requests
end
end
......
---
title: Rate limit project export by user
merge_request: 31719
author:
type: changed
......@@ -45,7 +45,7 @@ module API
end
end
post ':id/export' do
check_rate_limit! :project_export, [current_user, :project_export, user_project]
check_rate_limit! :project_export, [current_user, :project_export]
project_export_params = declared_params(include_missing: false)
after_export_params = project_export_params.delete(:upload) || {}
......
......@@ -1159,17 +1159,18 @@ describe ProjectsController do
end
shared_examples 'rate limits project export endpoint' do
before do
allow(::Gitlab::ApplicationRateLimiter)
.to receive(:throttled?)
.and_return(true)
end
it 'prevents requesting project export' do
post action, params: { namespace_id: project.namespace, id: project }
exportable_project = create(:project)
exportable_project.add_maintainer(user)
post action, params: { namespace_id: exportable_project.namespace, id: exportable_project }
expect(flash[:alert]).to eq('This endpoint has been requested too many times. Try again later.')
expect(response).to have_gitlab_http_status(:found)
post action, params: { namespace_id: project.namespace, id: project }
expect(response.body).to eq('This endpoint has been requested too many times. Try again later.')
expect(response).to have_gitlab_http_status(:too_many_requests)
end
end
......@@ -1226,7 +1227,18 @@ describe ProjectsController do
end
context 'when the endpoint receives requests above the limit', :clean_gitlab_redis_cache do
include_examples 'rate limits project export endpoint'
before do
allow(::Gitlab::ApplicationRateLimiter)
.to receive(:throttled?)
.and_return(true)
end
it 'prevents requesting project export' do
post action, params: { namespace_id: project.namespace, id: project }
expect(response.body).to eq('This endpoint has been requested too many times. Try again later.')
expect(response).to have_gitlab_http_status(:too_many_requests)
end
end
end
end
......
......@@ -44,19 +44,6 @@ describe API::ProjectExport, :clean_gitlab_redis_cache do
it_behaves_like '404 response'
end
shared_examples_for 'when rate limit is exceeded' do
before do
allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
end
it 'prevents requesting project export' do
request
expect(response).to have_gitlab_http_status(:too_many_requests)
expect(json_response['message']['error']).to eq('This endpoint has been requested too many times. Try again later.')
end
end
describe 'GET /projects/:project_id/export' do
shared_examples_for 'get project export status not found' do
it_behaves_like '404 response' do
......@@ -247,7 +234,16 @@ describe API::ProjectExport, :clean_gitlab_redis_cache do
context 'when rate limit is exceeded' do
let(:request) { get api(download_path, admin) }
include_examples 'when rate limit is exceeded'
before do
allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
end
it 'prevents requesting project export' do
request
expect(response).to have_gitlab_http_status(:too_many_requests)
expect(json_response['message']['error']).to eq('This endpoint has been requested too many times. Try again later.')
end
end
end
......@@ -360,10 +356,17 @@ describe API::ProjectExport, :clean_gitlab_redis_cache do
it_behaves_like 'post project export start'
context 'when rate limit is exceeded' do
let(:request) { post api(path, admin) }
context 'when rate limit is exceeded across projects' do
it 'prevents requesting project export' do
post api(path_none, admin)
expect(response).not_to have_gitlab_http_status(:too_many_requests)
post api(path, admin)
include_examples 'when rate limit is exceeded'
expect(response).to have_gitlab_http_status(:too_many_requests)
expect(json_response['message']['error']).to eq('This endpoint has been requested too many times. Try again later.')
end
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment