mirror of
https://github.com/discourse/discourse.git
synced 2024-11-29 20:24:05 -06:00
30990006a9
This reduces chances of errors where consumers of strings mutate inputs and reduces memory usage of the app. Test suite passes now, but there may be some stuff left, so we will run a few sites on a branch prior to merging
73 lines
1.9 KiB
Ruby
73 lines
1.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class RateLimiter
|
|
|
|
# A mixin we can use on ActiveRecord Models to automatically rate limit them
|
|
# based on a SiteSetting.
|
|
#
|
|
# It expects a SiteSetting called `rate_limit_create_{model_name}` where
|
|
# `model_name` is the class name of your model, underscored.
|
|
#
|
|
module OnCreateRecord
|
|
|
|
# Over write to define your own rate limiter
|
|
def default_rate_limiter
|
|
return @rate_limiter if @rate_limiter.present?
|
|
|
|
limit_key = "create_#{self.class.name.underscore}"
|
|
max_setting = if user && user.new_user? && SiteSetting.has_setting?("rate_limit_new_user_#{limit_key}")
|
|
SiteSetting.get("rate_limit_new_user_#{limit_key}")
|
|
else
|
|
SiteSetting.get("rate_limit_#{limit_key}")
|
|
end
|
|
@rate_limiter = RateLimiter.new(user, limit_key, 1, max_setting)
|
|
end
|
|
|
|
def self.included(base)
|
|
base.extend(ClassMethods)
|
|
end
|
|
|
|
# For the lifetime of this instance, don't enforce rate limits.
|
|
def disable_rate_limits!
|
|
@rate_limits_disabled = true
|
|
end
|
|
|
|
module ClassMethods
|
|
def rate_limit(limiter_method = nil)
|
|
|
|
limiter_method = limiter_method || :default_rate_limiter
|
|
|
|
self.after_create do |*args|
|
|
next if @rate_limits_disabled
|
|
|
|
if rate_limiter = public_send(limiter_method)
|
|
rate_limiter.performed!
|
|
@performed ||= {}
|
|
@performed[limiter_method] = true
|
|
end
|
|
end
|
|
|
|
self.after_destroy do
|
|
next if @rate_limits_disabled
|
|
if rate_limiter = public_send(limiter_method)
|
|
rate_limiter.rollback!
|
|
end
|
|
end
|
|
|
|
self.after_rollback do
|
|
next if @rate_limits_disabled
|
|
if rate_limiter = public_send(limiter_method)
|
|
if @performed.present? && @performed[limiter_method]
|
|
rate_limiter.rollback!
|
|
@performed[limiter_method] = false
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|