module Geocoder::Request

def geocoder_reject_non_ipv4_addresses(ip_addresses)

def geocoder_reject_non_ipv4_addresses(ip_addresses)
  ips = []
  for ip in ip_addresses
    begin
      valid_ip = IPAddr.new(ip)
    rescue
      valid_ip = false
    end
    ips << valid_ip.to_s if valid_ip
  end
  return ips.any? ? ips : ip_addresses
end

def geocoder_reject_trusted_ip_addresses(ip_addresses)

of our own proxy/load balancer)
default. (we don't want every lookup to return the location
been configured as trusted; includes private ranges by
use Rack's trusted_proxy?() method to filter out IPs that have
def geocoder_reject_trusted_ip_addresses(ip_addresses)
  ip_addresses.reject { |ip| trusted_proxy?(ip) }
end

def geocoder_remove_port_from_addresses(ip_addresses)

def geocoder_remove_port_from_addresses(ip_addresses)
  ip_addresses.map do |ip|
    # IPv4
    if ip.count('.') > 0
      ip.split(':').first
    # IPv6 bracket notation
    elsif match = ip.match(/\[(\S+)\]/)
      match.captures.first
    # IPv6 bare notation
    else
      ip
    end
  end
end

def geocoder_split_ip_addresses(ip_addresses)

def geocoder_split_ip_addresses(ip_addresses)
  ip_addresses ? ip_addresses.strip.split(/[,\s]+/) : []
end

def geocoder_spoofable_ip

def geocoder_spoofable_ip
  # We could use a more sophisticated IP-guessing algorithm here,
  # in which we'd try to resolve the use of different headers by
  # different proxies.  The idea is that by comparing IPs repeated
  # in different headers, you can sometimes decide which header
  # was used by a proxy further along in the chain, and thus
  # prefer the headers used earlier.  However, the gains might not
  # be worth the performance tradeoff, since this method is likely
  # to be called on every request in a lot of applications.
  GEOCODER_CANDIDATE_HEADERS.each do |header|
    if @env.has_key? header
      addrs = geocoder_split_ip_addresses(@env[header])
      addrs = geocoder_remove_port_from_addresses(addrs)
      addrs = geocoder_reject_non_ipv4_addresses(addrs)
      addrs = geocoder_reject_trusted_ip_addresses(addrs)
      return addrs.first if addrs.any?
    end
  end
  @env['REMOTE_ADDR']
end

def location

instead.
other security-sensitive application. Use safe_location
Don't use it in authorization/authentication code, or any
The location() method is vulnerable to trivial IP spoofing.
def location
  @location ||= Geocoder.search(geocoder_spoofable_ip, ip_address: true).first
end

def safe_location

through a non-whitelisted proxy.
corresponding to the original client IP for any request sent
not the original client IP. You WILL NOT get the location
location for the IP of the last untrusted proxy in the chain,
whitelisted as trusted in your Rack config, you will get the
For requests that go through a proxy that you haven't
This safe_location() protects you from trivial IP spoofing.
def safe_location
  @safe_location ||= Geocoder.search(ip, ip_address: true).first
end