| 
									
										
										
										
											2017-06-07 15:23:26 +00:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module RateLimitHeaders | 
					
						
							|  |  |  |   extend ActiveSupport::Concern | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-08 14:17:39 +00:00
										 |  |  |   class_methods do | 
					
						
							|  |  |  |     def override_rate_limit_headers(method_name, options = {}) | 
					
						
							|  |  |  |       around_action(only: method_name, if: :current_account) do |_controller, block| | 
					
						
							| 
									
										
										
										
											2023-02-18 22:09:40 +00:00
										 |  |  |         block.call | 
					
						
							|  |  |  |       ensure | 
					
						
							|  |  |  |         rate_limiter = RateLimiter.new(current_account, options) | 
					
						
							|  |  |  |         rate_limit_headers = rate_limiter.to_headers | 
					
						
							|  |  |  |         response.headers.merge!(rate_limit_headers) unless response.headers['X-RateLimit-Remaining'].present? && rate_limit_headers['X-RateLimit-Remaining'].to_i > response.headers['X-RateLimit-Remaining'].to_i | 
					
						
							| 
									
										
										
										
											2020-03-08 14:17:39 +00:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-07 15:23:26 +00:00
										 |  |  |   included do | 
					
						
							|  |  |  |     before_action :set_rate_limit_headers, if: :rate_limited_request? | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def set_rate_limit_headers | 
					
						
							|  |  |  |     apply_header_limit | 
					
						
							|  |  |  |     apply_header_remaining | 
					
						
							|  |  |  |     apply_header_reset | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def rate_limited_request? | 
					
						
							|  |  |  |     !request.env['rack.attack.throttle_data'].nil? | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def apply_header_limit | 
					
						
							|  |  |  |     response.headers['X-RateLimit-Limit'] = rate_limit_limit | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def rate_limit_limit | 
					
						
							|  |  |  |     api_throttle_data[:limit].to_s | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def apply_header_remaining | 
					
						
							|  |  |  |     response.headers['X-RateLimit-Remaining'] = rate_limit_remaining | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def rate_limit_remaining | 
					
						
							|  |  |  |     (api_throttle_data[:limit] - api_throttle_data[:count]).to_s | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def apply_header_reset | 
					
						
							|  |  |  |     response.headers['X-RateLimit-Reset'] = rate_limit_reset | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def rate_limit_reset | 
					
						
							|  |  |  |     (request_time + reset_period_offset).iso8601(6) | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def api_throttle_data | 
					
						
							| 
									
										
										
										
											2022-12-15 16:11:58 +00:00
										 |  |  |     most_limited_type, = request.env['rack.attack.throttle_data'].min_by { |_key, value| value[:limit] - value[:count] } | 
					
						
							| 
									
										
										
										
											2017-12-11 14:32:29 +00:00
										 |  |  |     request.env['rack.attack.throttle_data'][most_limited_type] | 
					
						
							| 
									
										
										
										
											2017-06-07 15:23:26 +00:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def request_time | 
					
						
							|  |  |  |     @_request_time ||= Time.now.utc | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def reset_period_offset | 
					
						
							| 
									
										
										
										
											2023-02-18 03:30:23 +00:00
										 |  |  |     api_throttle_data[:period] - (request_time.to_i % api_throttle_data[:period]) | 
					
						
							| 
									
										
										
										
											2017-06-07 15:23:26 +00:00
										 |  |  |   end | 
					
						
							|  |  |  | end |