|
|
|
|
- Class "RateLimit" has 301 lines. It should have 300 or less. » roodi
|
3class RateLimit < ActiveRecord::Base
|
|
4 GLOB_PATTERN = /^(\*\*\.|\*\.)/
|
|
|
|
6 RECURSIVE_PATTERN = "(?:[-a-z0-9]+\\.)+"
|
|
|
|
8 SINGLE_PATTERN = "(?:[-a-z0-9]+\\.)"
|
|
9 DOMAIN_PATTERN = /^(?:[a-z0-9][a-z0-9-]{0,61}[a-z0-9]\.)+[a-z]{2,}$/
|
|
|
|
11 validates :burst_rate, presence: true, numericality: { only_integer: true, greater_than: 0 }
|
|
12 validates :burst_period, presence: true, numericality: { only_integer: true, greater_than: 0 }
|
|
13 validates :sustained_rate, presence: true, numericality: { only_integer: true, greater_than: 0 }
|
|
14 validates :sustained_period, presence: true, numericality: { only_integer: true, greater_than: 0 }
|
|
15 validates :allowed_domains, length: { maximum: 10000, allow_blank: true }
|
|
16 validates :allowed_ips, length: { maximum: 10000, allow_blank: true }
|
|
17 validates :blocked_domains, length: { maximum: 50000, allow_blank: true }
|
|
18 validates :blocked_ips, length: { maximum: 50000, allow_blank: true }
|
|
19 validates :countries, length: { maximum: 2000, allow_blank: true }
|
|
20 validates :country_burst_rate, presence: true, numericality: { only_integer: true, greater_than: 0 }
|
|
21 validates :country_sustained_rate, presence: true, numericality: { only_integer: true, greater_than: 0 }
|
|
22 validates :threshold_for_form_entry, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
|
23 validates :threshold_for_logging_trending_items, presence: true, numericality: { only_integer: true, greater_than: 0 }
|
|
24 validates :threshold_for_notifying_trending_items, presence: true, numericality: { only_integer: true, greater_than: 0 }
|
|
25 validates :trending_items_notification_url, length: { maximum: 100, allow_blank: true }
|
|
26 validates :ignored_domains, length: { maximum: 10000, allow_blank: true }
|
|
|
- Block cyclomatic complexity is 15. It should be 4 or less. » roodi
|
|
|
29 unless sustained_rate.nil? || burst_rate.nil?
|
|
30 if sustained_rate <= burst_rate
|
|
31 errors.add :sustained_rate, "Sustained rate must be greater than burst rate"
|
|
|
|
|
|
|
|
35 unless sustained_period.nil? || burst_period.nil?
|
|
36 if sustained_period <= burst_period
|
|
37 errors.add :sustained_period, "Sustained period must be greater than burst period"
|
|
|
|
|
|
|
|
41 unless country_sustained_rate.nil? || country_burst_rate.nil?
|
|
42 if country_sustained_rate <= country_burst_rate
|
|
43 errors.add :country_sustained_rate, "Country sustained rate must be greater than country burst rate"
|
|
|
|
|
|
|
|
|
|
|
|
49 rescue StandardError => e
|
|
50 errors.add :allowed_domains, :invalid
|
|
|
|
|
|
|
|
|
|
55 rescue StandardError => e
|
|
56 errors.add :allowed_ips, :invalid
|
|
|
|
|
|
|
|
|
|
61 rescue StandardError => e
|
|
62 errors.add :blocked_domains, :invalid
|
|
|
|
|
|
|
|
|
|
67 rescue StandardError => e
|
|
68 errors.add :blocked_ips, :invalid
|
|
|
|
|
|
|
|
|
|
73 rescue StandardError => e
|
|
74 errors.add :ignored_domains, :invalid
|
|
|
|
|
|
|
- TooManyStatements - has approx 7 statements » reek
- Complexity 1 » saikuro
|
|
|
79 @allowed_domains_list = nil
|
|
80 @blocked_domains_list = nil
|
|
81 @allowed_ips_list = nil
|
|
82 @blocked_ips_list = nil
|
|
83 @allowed_countries = nil
|
|
84 @ignored_domains_list = nil
|
|
|
|
|
|
|
|
|
- DuplicateMethodCall - calls 'signature.domain' 2 times » reek
- DuplicateMethodCall - calls 'signature.ip_address' 4 times » reek
- TooManyStatements - has approx 8 statements » reek
- Complexity 8 » saikuro
|
89 def exceeded?(signature)
|
|
90 return true unless threshold_reached?(signature)
|
|
91 return true if ip_blocked?(signature.ip_address)
|
|
92 return true if ip_geoblocked?(signature.ip_address)
|
|
93 return true if domain_blocked?(signature.domain)
|
|
94 return false if ip_allowed?(signature.ip_address)
|
|
95 return false if domain_allowed?(signature.domain)
|
|
|
|
97 if use_country_rate?(signature.ip_address)
|
|
98 country_rate_exceeded?(signature)
|
|
|
|
100 rate_exceeded?(signature)
|
|
|
|
|
|
|
|
104 def ignore_domain?(domain)
|
|
105 domain_blocked?(domain) || domain_allowed?(domain)
|
|
|
|
|
|
|
|
109 ip_blocked?(ip) || ip_allowed?(ip) || ip_geoblocked?(ip)
|
|
|
|
|
|
112 def allowed_domains=(value)
|
|
113 @allowed_domains_list = nil
|
|
114 super(normalize_lines(value))
|
|
|
|
|
|
117 def allowed_domains_list
|
|
118 @allowed_domains_list ||= build_allowed_domains
|
|
|
|
|
|
121 def blocked_domains=(value)
|
|
122 @blocked_domains_list = nil
|
|
123 super(normalize_lines(value))
|
|
|
|
|
|
126 def blocked_domains_list
|
|
127 @blocked_domains_list ||= build_blocked_domains
|
|
|
|
|
|
130 def allowed_ips=(value)
|
|
131 @allowed_ips_list = nil
|
|
132 super(normalize_lines(value))
|
|
|
|
|
|
|
|
136 @allowed_ips_list ||= build_allowed_ips
|
|
|
|
|
|
139 def blocked_ips=(value)
|
|
140 @blocked_ips_list = nil
|
|
141 super(normalize_lines(value))
|
|
|
|
|
|
|
|
145 @blocked_ips_list ||= build_blocked_ips
|
|
|
|
|
|
148 def allowed_countries
|
|
149 @allowed_countries ||= build_allowed_countries
|
|
|
|
|
|
152 def countries=(value)
|
|
153 @allowed_countries = nil
|
|
154 super(normalize_lines(value))
|
|
|
|
|
|
157 def ignored_domains=(value)
|
|
158 @ignored_domains_list = nil
|
|
159 super(normalize_lines(value))
|
|
|
|
|
|
162 def ignored_domains_list
|
|
163 @ignored_domains_list ||= build_ignored_domains
|
|
|
|
|
|
|
|
|
- UtilityFunction - doesn't depend on instance state (maybe move it to another class?) » reek
- Complexity 1 » saikuro
|
168 def strip_comments(list)
|
|
169 list.gsub(/#.*$/, '')
|
|
|
|
|
- UtilityFunction - doesn't depend on instance state (maybe move it to another class?) » reek
- Complexity 1 » saikuro
|
172 def strip_blank_lines(list)
|
|
173 list.each_line.reject(&:blank?)
|
|
|
|
|
- UncommunicativeVariableName - has the variable name 'l' » reek
- Complexity 2 » saikuro
|
176 def build_allowed_domains
|
|
177 domains = strip_comments(allowed_domains)
|
|
178 domains = strip_blank_lines(domains)
|
|
|
|
180 domains.map{ |l| %r[\A#{convert_glob(l.strip)}\z] }
|
|
|
|
|
- UncommunicativeVariableName - has the variable name 'd' » reek
- Complexity 2 » saikuro
|
183 def domain_allowed?(domain)
|
|
184 allowed_domains_list.any?{ |d| d === domain }
|
|
|
|
|
- UncommunicativeVariableName - has the variable name 'l' » reek
- Complexity 2 » saikuro
|
187 def build_blocked_domains
|
|
188 domains = strip_comments(blocked_domains)
|
|
189 domains = strip_blank_lines(domains)
|
|
|
|
191 domains.map{ |l| %r[\A#{convert_glob(l.strip)}\z] }
|
|
|
|
|
- UncommunicativeVariableName - has the variable name 'd' » reek
- Complexity 2 » saikuro
|
194 def domain_blocked?(domain)
|
|
195 blocked_domains_list.any?{ |d| d === domain }
|
|
|
|
|
- UncommunicativeVariableName - has the variable name 'l' » reek
- Complexity 2 » saikuro
|
198 def build_allowed_ips
|
|
199 ips = strip_comments(allowed_ips)
|
|
200 ips = strip_blank_lines(ips)
|
|
|
|
202 ips.map{ |l| IPAddr.new(l.strip) }
|
|
|
|
|
- UncommunicativeVariableName - has the variable name 'i' » reek
- Complexity 2 » saikuro
|
|
|
206 allowed_ips_list.any?{ |i| i.include?(ip) }
|
|
|
|
|
- UncommunicativeVariableName - has the variable name 'l' » reek
- Complexity 2 » saikuro
|
209 def build_blocked_ips
|
|
210 ips = strip_comments(blocked_ips)
|
|
211 ips = strip_blank_lines(ips)
|
|
|
|
213 ips.map{ |l| IPAddr.new(l.strip) }
|
|
|
|
|
- UncommunicativeVariableName - has the variable name 'i' » reek
- Complexity 2 » saikuro
|
|
|
217 blocked_ips_list.any?{ |i| i.include?(ip) }
|
|
|
|
|
- UncommunicativeVariableName - has the variable name 'd' » reek
- Complexity 2 » saikuro
|
220 def build_ignored_domains
|
|
221 strip_blank_lines(strip_comments(ignored_domains)).map { |d| validate_domain!(d.strip) }
|
|
|
|
|
|
224 def build_allowed_countries
|
|
225 strip_blank_lines(strip_comments(countries)).map(&:strip)
|
|
|
|
|
|
228 def ip_geoblocked?(ip)
|
|
229 geoblocking_enabled? && country_blocked?(ip)
|
|
|
|
|
|
232 def country_blocked?(ip)
|
|
233 allowed_countries.exclude?(country_for_ip(ip))
|
|
|
|
|
- FeatureEnvy - refers to 'result' more than self (maybe move it to another class?) » reek
- Complexity 2 » saikuro
|
236 def country_for_ip(ip)
|
|
237 result = geoip_db.lookup(ip)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
247 @geoip_db ||= MaxMindDB.new(ENV.fetch('GEOIP_DB_PATH'))
|
|
|
|
|
- UtilityFunction - doesn't depend on instance state (maybe move it to another class?) » reek
- Complexity 4 » saikuro
|
250 def convert_glob(pattern)
|
|
251 pattern.gsub(GLOB_PATTERN) do |match|
|
|
252 if match == RECURSIVE_GLOB
|
|
|
|
254 elsif match == SINGLE_GLOB
|
|
|
|
|
|
|
|
|
|
|
- FeatureEnvy - refers to 'domain' more than self (maybe move it to another class?) » reek
- Complexity 2 » saikuro
|
260 def validate_domain!(domain)
|
|
261 if domain =~ DOMAIN_PATTERN
|
|
|
|
|
|
264 raise ArgumentError, "Invalid domain: #{domain.inspect}"
|
|
|
|
|
|
|
- UtilityFunction - doesn't depend on instance state (maybe move it to another class?) » reek
- Complexity 1 » saikuro
|
268 def normalize_lines(value)
|
|
269 value.to_s.strip.gsub(/\r\n|\r/, "\n")
|
|
|
|
|
|
272 def use_country_rate?(ip)
|
|
273 if country_rate_limits_enabled?
|
|
274 allowed_countries.include?(country_for_ip(ip))
|
|
|
|
|
|
|
|
|
|
|
|
280 def country_rate_exceeded?(signature)
|
|
281 country_burst_rate_exceeded?(signature) || country_sustained_rate_exceeded?(signature)
|
|
|
|
|
|
284 def country_burst_rate_exceeded?(signature)
|
|
285 country_burst_rate < signature.rate(burst_period)
|
|
|
|
|
|
288 def country_sustained_rate_exceeded?(signature)
|
|
289 country_sustained_rate < signature.rate(sustained_period)
|
|
|
|
|
|
292 def rate_exceeded?(signature)
|
|
293 burst_rate_exceeded?(signature) || sustained_rate_exceeded?(signature)
|
|
|
|
|
|
296 def burst_rate_exceeded?(signature)
|
|
297 burst_rate < signature.rate(burst_period)
|
|
|
|
|
|
300 def sustained_rate_exceeded?(signature)
|
|
301 sustained_rate < signature.rate(sustained_period)
|
|
|
|
|
- FeatureEnvy - refers to 'signature' more than self (maybe move it to another class?) » reek
- Complexity 5 » saikuro
|
304 def threshold_reached?(signature)
|
|
305 return true unless threshold_for_form_entry?
|
|
306 return false unless signature.image_loaded_at?
|
|
307 return false unless signature.form_requested_at?
|
|
308 return false if signature.form_token_reused?
|
|
|
|
310 signature.form_duration > threshold_for_form_entry
|
|
|
|
|