Merge remote-tracking branch 'upstream/pull/4198'
This commit is contained in:
commit
3422bb541d
4 changed files with 82 additions and 1 deletions
|
@ -186,6 +186,9 @@ class UsersController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
if current_user.save
|
if current_user.save
|
||||||
|
SIGNUP_IP_LIMITER&.update(request.remote_ip)
|
||||||
|
SIGNUP_EMAIL_LIMITER&.update(canonical_email(current_user.email))
|
||||||
|
|
||||||
flash[:matomo_goal] = Settings.matomo["goals"]["signup"] if defined?(Settings.matomo)
|
flash[:matomo_goal] = Settings.matomo["goals"]["signup"] if defined?(Settings.matomo)
|
||||||
|
|
||||||
referer = welcome_path
|
referer = welcome_path
|
||||||
|
@ -344,7 +347,13 @@ class UsersController < ApplicationController
|
||||||
domain_mx_servers(domain)
|
domain_mx_servers(domain)
|
||||||
end
|
end
|
||||||
|
|
||||||
if blocked = Acl.no_account_creation(request.remote_ip, :domain => domain, :mx => mx_servers)
|
blocked = Acl.no_account_creation(request.remote_ip, :domain => domain, :mx => mx_servers)
|
||||||
|
|
||||||
|
blocked ||= SIGNUP_IP_LIMITER && !SIGNUP_IP_LIMITER.allow?(request.remote_ip)
|
||||||
|
|
||||||
|
blocked ||= email && SIGNUP_EMAIL_LIMITER && !SIGNUP_EMAIL_LIMITER.allow?(canonical_email(email))
|
||||||
|
|
||||||
|
if blocked
|
||||||
logger.info "Blocked signup from #{request.remote_ip} for #{email}"
|
logger.info "Blocked signup from #{request.remote_ip} for #{email}"
|
||||||
|
|
||||||
render :action => "blocked"
|
render :action => "blocked"
|
||||||
|
@ -353,6 +362,20 @@ class UsersController < ApplicationController
|
||||||
!blocked
|
!blocked
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def canonical_email(email)
|
||||||
|
local_part, domain = if email.nil?
|
||||||
|
nil
|
||||||
|
else
|
||||||
|
email.split("@")
|
||||||
|
end
|
||||||
|
|
||||||
|
local_part.sub!(/\+.*$/, "")
|
||||||
|
|
||||||
|
local_part.delete!(".") if %w[gmail.com googlemail.com].include?(domain)
|
||||||
|
|
||||||
|
"#{local_part}@#{domain}"
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# get list of MX servers for a domains
|
# get list of MX servers for a domains
|
||||||
def domain_mx_servers(domain)
|
def domain_mx_servers(domain)
|
||||||
|
|
15
config/initializers/rate_limits.rb
Normal file
15
config/initializers/rate_limits.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
require "rate_limiter"
|
||||||
|
|
||||||
|
SIGNUP_IP_LIMITER = if Settings.memcache_servers && Settings.signup_ip_per_day && Settings.signup_ip_max_burst
|
||||||
|
RateLimiter.new(
|
||||||
|
Dalli::Client.new(Settings.memcache_servers, :namespace => "rails:signup:ip"),
|
||||||
|
86400, Settings.signup_ip_per_day, Settings.signup_ip_max_burst
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
SIGNUP_EMAIL_LIMITER = if Settings.memcache_servers && Settings.signup_email_per_day && Settings.signup_email_max_burst
|
||||||
|
RateLimiter.new(
|
||||||
|
Dalli::Client.new(Settings.memcache_servers, :namespace => "rails:signup:email"),
|
||||||
|
86400, Settings.signup_email_per_day, Settings.signup_email_max_burst
|
||||||
|
)
|
||||||
|
end
|
|
@ -140,3 +140,8 @@ smtp_user_name: null
|
||||||
smtp_password: null
|
smtp_password: null
|
||||||
# Matomo settings for analytics
|
# Matomo settings for analytics
|
||||||
#matomo:
|
#matomo:
|
||||||
|
# Signup rate limits
|
||||||
|
#signup_ip_per_day:
|
||||||
|
#signup_ip_max_burst:
|
||||||
|
#signup_email_per_day:
|
||||||
|
#signup_email_max_burst:
|
||||||
|
|
38
lib/rate_limiter.rb
Normal file
38
lib/rate_limiter.rb
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
class RateLimiter
|
||||||
|
def initialize(cache, interval, limit, max_burst)
|
||||||
|
@cache = cache
|
||||||
|
@requests_per_second = limit.to_f / interval
|
||||||
|
@burst_limit = max_burst
|
||||||
|
end
|
||||||
|
|
||||||
|
def allow?(key)
|
||||||
|
last_update, requests = @cache.get(key)
|
||||||
|
|
||||||
|
if last_update
|
||||||
|
elapsed = Time.now.to_i - last_update
|
||||||
|
|
||||||
|
requests -= elapsed * @requests_per_second
|
||||||
|
else
|
||||||
|
requests = 0.0
|
||||||
|
end
|
||||||
|
|
||||||
|
requests < @burst_limit
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(key)
|
||||||
|
now = Time.now.to_i
|
||||||
|
|
||||||
|
last_update, requests = @cache.get(key)
|
||||||
|
|
||||||
|
if last_update
|
||||||
|
elapsed = now - last_update
|
||||||
|
|
||||||
|
requests -= elapsed * @requests_per_second
|
||||||
|
requests += 1.0
|
||||||
|
else
|
||||||
|
requests = 1.0
|
||||||
|
end
|
||||||
|
|
||||||
|
@cache.set(key, [now, [requests, 1.0].max])
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Add a link
Reference in a new issue