Skip to content

Commit

Permalink
Merge pull request #46 from ipinfo/saad/support-for-ipv6-host
Browse files Browse the repository at this point in the history
Support for IPv6 Host
  • Loading branch information
UmanShahzad authored Jan 3, 2024
2 parents fa00489 + 46c8ab5 commit 1956b1b
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 71 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ handler = IPinfo::create(access_token)
ip_address = '216.239.36.21'

details = handler.details(ip_address)
details_v6 = handler.details_v6() # to get details from ipinfo's IPv6 host
city = details.city # Emeryville
loc = details.loc # 37.8342,-122.2900
```
Expand All @@ -58,7 +59,7 @@ require 'ipinfo' unless defined?(IPinfo)

#### Usage

The `IPinfo.details()` method accepts an IP address as an optional, positional
The `IPinfo.details()` and `IPinfo.details_v6()` methods accept an IP address as an optional, positional
argument. If no IP address is specified, the API will return data for the IP
address from which it receives the request.

Expand All @@ -69,6 +70,7 @@ access_token = '123456789abc'
handler = IPinfo::create(access_token)

details = handler.details()
details_v6 = handler.details_v6() # to get details from ipinfo's IPv6 host
city = details.city # "Emeryville"
loc = details.loc # 37.8342,-122.2900
```
Expand All @@ -86,7 +88,7 @@ handler = IPinfo::create(access_token)

#### Details Data

`handler.details()` will return a `Response` object that contains all fields
`handler.details()` and `handler.details_v6` will return a `Response` object that contains all fields
listed in the [IPinfo developerdocs](https://ipinfo.io/developers/responses#full-response)
with a few minor additions. Properties can be accessed directly.

Expand Down
78 changes: 41 additions & 37 deletions lib/ipinfo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class IPinfo::IPinfo

def initialize(access_token = nil, settings = {})
@access_token = access_token
@httpc = prepare_http_client(settings.fetch('http_client', nil))
prepare_http_client(settings.fetch('http_client', nil))

maxsize = settings.fetch('maxsize', DEFAULT_CACHE_MAXSIZE)
ttl = settings.fetch('ttl', DEFAULT_CACHE_TTL)
Expand All @@ -47,33 +47,11 @@ def initialize(access_token = nil, settings = {})
end

def details(ip_address = nil)
details = request_details(ip_address)
if details.key? :country
details[:country_name] =
@countries.fetch(details.fetch(:country), nil)
details[:is_eu] =
@eu_countries.include?(details.fetch(:country))
details[:country_flag] =
@countries_flags.fetch(details.fetch(:country), nil)
details[:country_currency] =
@countries_currencies.fetch(details.fetch(:country), nil)
details[:continent] =
@continents.fetch(details.fetch(:country), nil)
details[:country_flag_url] = COUNTRY_FLAGS_URL + details.fetch(:country) + ".svg"
end

if details.key? :ip
details[:ip_address] =
IPAddr.new(details.fetch(:ip))
end

if details.key? :loc
loc = details.fetch(:loc).split(',')
details[:latitude] = loc[0]
details[:longitude] = loc[1]
end
details_base(ip_address, :v4)
end

Response.new(details)
def details_v6(ip_address = nil)
details_base(ip_address, :v6)
end

def get_map_url(ips)
Expand Down Expand Up @@ -133,7 +111,13 @@ def batch_requests(url_array, api_token)

protected

def request_details(ip_address = nil)
def prepare_http_client(httpc = nil)
@httpc = Adapter.new(access_token, httpc || :net_http)
end

private

def request_details(ip_address = nil, host_type)
if isBogon(ip_address)
details[:ip] = ip_address
details[:bogon] = true
Expand All @@ -145,7 +129,7 @@ def request_details(ip_address = nil)
res = @cache.get(cache_key(ip_address))
return res unless res.nil?

response = @httpc.get(escape_path(ip_address))
response = @httpc.get(escape_path(ip_address), host_type)

if response.status.eql?(429)
raise RateLimitError,
Expand All @@ -157,15 +141,35 @@ def request_details(ip_address = nil)
details
end

def prepare_http_client(httpc = nil)
@httpc = if httpc
Adapter.new(access_token, httpc)
else
Adapter.new(access_token)
end
end
def details_base(ip_address, host_type)
details = request_details(ip_address, host_type)
if details.key? :country
details[:country_name] =
@countries.fetch(details.fetch(:country), nil)
details[:is_eu] =
@eu_countries.include?(details.fetch(:country))
details[:country_flag] =
@countries_flags.fetch(details.fetch(:country), nil)
details[:country_currency] =
@countries_currencies.fetch(details.fetch(:country), nil)
details[:continent] =
@continents.fetch(details.fetch(:country), nil)
details[:country_flag_url] = COUNTRY_FLAGS_URL + details.fetch(:country) + ".svg"
end

private
if details.key? :ip
details[:ip_address] =
IPAddr.new(details.fetch(:ip))
end

if details.key? :loc
loc = details.fetch(:loc).split(',')
details[:latitude] = loc[0]
details[:longitude] = loc[1]
end

Response.new(details)
end

def isBogon(ip)
if ip.nil?
Expand Down
15 changes: 9 additions & 6 deletions lib/ipinfo/adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
require 'faraday'
require 'cgi'
require 'ipinfo/mod'
require_relative './version.rb'

class IPinfo::Adapter
HOST = 'ipinfo.io'
HOST = 'https://ipinfo.io'
HOST_V6 = 'https://v6.ipinfo.io'

attr_reader :conn

Expand All @@ -14,8 +16,9 @@ def initialize(token = nil, adapter = :net_http)
@conn = connection(adapter)
end

def get(uri)
@conn.get(uri) do |req|
def get(uri, host_type= :v4)
host = (host_type == :v6) ? HOST_V6 : HOST
@conn.get(host + uri) do |req|
default_headers.each_pair do |key, value|
req.headers[key] = value
end
Expand All @@ -24,7 +27,7 @@ def get(uri)
end

def post(uri, body, timeout = 2)
@conn.post(uri) do |req|
@conn.post(HOST + uri) do |req|
req.body = body
req.options.timeout = timeout
end
Expand All @@ -35,14 +38,14 @@ def post(uri, body, timeout = 2)
attr_reader :token

def connection(adapter)
Faraday.new(url: "https://#{HOST}") do |conn|
Faraday.new() do |conn|
conn.adapter(adapter)
end
end

def default_headers
headers = {
'User-Agent' => 'IPinfoClient/Ruby/2.1.0',
'User-Agent' => "IPinfoClient/Ruby/#{IPinfo::VERSION}",
'Accept' => 'application/json'
}
headers['Authorization'] = "Bearer #{CGI.escape(token)}" if token
Expand Down
2 changes: 1 addition & 1 deletion lib/ipinfo/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module IPinfo
VERSION = '2.1.0'
VERSION = '2.2.0'
end
72 changes: 47 additions & 25 deletions test/ipinfo_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,6 @@ class IPinfoTest < Minitest::Test
TEST_IPV4 = '8.8.8.8'
TEST_IPV6 = '2601:9:7680:363:75df:f491:6f85:352f'

def test_that_it_has_a_version_number
refute_nil ::IPinfo::VERSION
end

def test_set_adapter
ipinfo = IPinfo.create(
ENV['IPINFO_TOKEN'],
{ http_client: :excon }
)

assert(ipinfo.httpc = :excon)
end

def assert_ip6(resp)
assert_equal(resp.ip, TEST_IPV6)
assert_equal(resp.ip_address, IPAddr.new(TEST_IPV6))
Expand Down Expand Up @@ -48,7 +35,7 @@ def assert_ip6(resp)
{
"name": 'Comcast Cable Communications, LLC',
"domain": 'comcast.com',
"type": ''
"type": 'isp'
}
)
assert_equal(
Expand Down Expand Up @@ -84,16 +71,6 @@ def assert_ip6(resp)
)
end

def test_lookup_ip6
ipinfo = IPinfo.create(ENV['IPINFO_TOKEN'])

# multiple checks for cache
(0...5).each do |_|
resp = ipinfo.details(TEST_IPV6)
assert_ip6(resp)
end
end

def assert_ip4(resp)
assert_equal(resp.ip, TEST_IPV4)
assert_equal(resp.ip_address, IPAddr.new(TEST_IPV4))
Expand Down Expand Up @@ -149,7 +126,7 @@ def assert_ip4(resp)
resp.abuse,
{
"address": 'US, CA, Mountain View, ' \
'1600 Amphitheatre Parkway, 94043',
'1600 Amphitheatre Parkway, 94043',
"country": 'US',
"email": '[email protected]',
"name": 'Abuse',
Expand All @@ -162,6 +139,40 @@ def assert_ip4(resp)
refute_nil(resp.domains[:domains])
end

def test_that_it_has_a_version_number
refute_nil ::IPinfo::VERSION
end

def test_set_adapter_v4
ipinfo = IPinfo.create(
ENV['IPINFO_TOKEN'],
{ http_client: :excon }
)

assert(ipinfo.httpc = :excon)
end

def test_lookup_ip6
ipinfo = IPinfo.create(ENV['IPINFO_TOKEN'])

# multiple checks for cache
(0...5).each do |_|
resp = ipinfo.details(TEST_IPV6)
assert_ip6(resp)
end
end

# # Requires IPv6 support
# def test_lookup_ip6_on_host_v6
# ipinfo = IPinfo.create(ENV['IPINFO_TOKEN'])

# # multiple checks for cache
# (0...5).each do |_|
# resp = ipinfo.details_v6(TEST_IPV6)
# assert_ip6(resp)
# end
# end

def test_lookup_ip4
ipinfo = IPinfo.create(ENV['IPINFO_TOKEN'])

Expand All @@ -171,4 +182,15 @@ def test_lookup_ip4
assert_ip4(resp)
end
end

# # Requires IPv6 support
# def test_lookup_ip4_on_host_v6
# ipinfo = IPinfo.create(ENV['IPINFO_TOKEN'])

# # multiple checks for cache
# (0...5).each do |_|
# resp = ipinfo.details_v6(TEST_IPV4)
# assert_ip4(resp)
# end
# end
end

0 comments on commit 1956b1b

Please sign in to comment.