Skip to content

Commit

Permalink
Limit number of cover image uploads (forem#2851)
Browse files Browse the repository at this point in the history
  • Loading branch information
jessleenyc authored and maestromac committed May 17, 2019
1 parent bd22edc commit b935fdd
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 0 deletions.
12 changes: 12 additions & 0 deletions app/controllers/image_uploads_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ def create

uploader = ArticleImageUploader.new
begin
raise RateLimitChecker::UploadRateLimitReached if RateLimitChecker.new(current_user).limit_by_situation("image_upload")

uploader.store!(params[:image])
RateLimitChecker.new(current_user).track_image_uploads
rescue RateLimitChecker::UploadRateLimitReached
respond_to do |format|
format.json { render json: { error: "Upload limit reached!" } }
end
return
rescue CarrierWave::IntegrityError => e # client error
respond_to do |format|
format.json { render json: { error: e.message }, status: :unprocessable_entity }
Expand All @@ -20,6 +28,10 @@ def create
return
end

cloudinary_link(uploader)
end

def cloudinary_link(uploader)
link = if params[:wrap_cloudinary]
ApplicationController.helpers.cloud_cover_url(uploader.url)
else
Expand Down
10 changes: 10 additions & 0 deletions app/labor/rate_limit_checker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,29 @@ def initialize(user = nil)
@user = user
end

class UploadRateLimitReached < StandardError; end

def limit_by_situation(situation)
result = case situation
when "comment_creation"
user.comments.where("created_at > ?", 30.seconds.ago).size > 9
when "published_article_creation"
user.articles.published.where("created_at > ?", 30.seconds.ago).size > 9
when "image_upload"
Rails.cache.read("#{user.id}_image_upload").to_i > 9
else
false
end
ping_admins if result == true
result
end

def track_image_uploads
count = Rails.cache.read("#{@user.id}_image_upload").to_i
count += 1
Rails.cache.write("#{@user.id}_image_upload", count, expires_in: 30.seconds)
end

def limit_by_email_recipient_address(address)
# This is related to the recipient, not the "user" initiator, like in situation.
EmailMessage.where(to: address).
Expand Down
26 changes: 26 additions & 0 deletions spec/requests/image_uploads_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"image/jpeg",
)
end
let(:memory_store) { ActiveSupport::Cache.lookup_store(:memory_store) }
let(:cache) { Rails.cache }
let(:bad_image) do
Rack::Test::UploadedFile.new(
Rails.root.join("spec", "support", "fixtures", "images", "bad-image.jpg"),
Expand Down Expand Up @@ -51,5 +53,29 @@
expect(result["error"]).not_to be_nil
end
end

context "when uploading rate limiting works" do
before do
sign_in user
allow(Rails).to receive(:cache).and_return(memory_store)
Rails.cache.clear
end

it "counts number of uploads in cache" do
post "/image_uploads", headers: headers, params: { image: image }
expect(cache.read("#{user.id}_image_upload")).to eq(1)
end

it "raises error with too many uploads" do
upload = proc do
Rack::Test::UploadedFile.new(
Rails.root.join("spec", "support", "fixtures", "images", "images1.jpeg"), "image/jpeg"
)
end
expect do
11.times { post "/image_uploads", headers: headers, params: { image: upload.call } }
end.to raise_error(RuntimeError)
end
end
end
end

0 comments on commit b935fdd

Please sign in to comment.