IPinfo 2.3.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/ipinfo/adapter.rb +78 -0
- data/lib/ipinfo/version.rb +1 -1
- data/lib/ipinfo_core.rb +124 -0
- data/lib/ipinfo_lite.rb +1 -1
- data/lib/ipinfo_plus.rb +124 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 908f27e7bc10bccd5d91c5697e53ef43c3399f497a797596cba28403e5fb7769
|
|
4
|
+
data.tar.gz: 93805a37bd2528f8f335bdfacb7c8367a8c95f4cf6728f5f9a7fbb216daeb831
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f5178a2fee807837d3385b3e3fb00098aac28b54480d6492e11fc5e30de7ec92cd16d0c3bfb4685be15c3dfa18b2b6db44f8bc01568a63ba3fd24375421d6c11
|
|
7
|
+
data.tar.gz: 811a19e8a55e9a06b84e075c36d4ce52e8d127f0d5bacf944b142b0318c934d39229261e22e96a271ecf2c816175262c48e35cc593d93429880ed485e6f0c3cd
|
data/lib/ipinfo/adapter.rb
CHANGED
|
@@ -91,3 +91,81 @@ class IPinfo::AdapterLite
|
|
|
91
91
|
headers
|
|
92
92
|
end
|
|
93
93
|
end
|
|
94
|
+
|
|
95
|
+
class IPinfo::AdapterCore
|
|
96
|
+
HOST = 'https://api.ipinfo.io/lookup'
|
|
97
|
+
|
|
98
|
+
attr_reader :conn
|
|
99
|
+
|
|
100
|
+
def initialize(token = nil, adapter = :net_http)
|
|
101
|
+
@token = token
|
|
102
|
+
@conn = connection(adapter)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def get(uri)
|
|
106
|
+
@conn.get(HOST + uri) do |req|
|
|
107
|
+
default_headers.each_pair do |key, value|
|
|
108
|
+
req.headers[key] = value
|
|
109
|
+
end
|
|
110
|
+
req.params['token'] = CGI.escape(token) if token
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
attr_reader :token
|
|
117
|
+
|
|
118
|
+
def connection(adapter)
|
|
119
|
+
Faraday.new() do |conn|
|
|
120
|
+
conn.adapter(adapter)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def default_headers
|
|
125
|
+
headers = {
|
|
126
|
+
'User-Agent' => "IPinfoClient/Ruby/#{IPinfo::VERSION}",
|
|
127
|
+
'Accept' => 'application/json'
|
|
128
|
+
}
|
|
129
|
+
headers['Authorization'] = "Bearer #{CGI.escape(token)}" if token
|
|
130
|
+
headers
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
class IPinfo::AdapterPlus
|
|
135
|
+
HOST = 'https://api.ipinfo.io/lookup'
|
|
136
|
+
|
|
137
|
+
attr_reader :conn
|
|
138
|
+
|
|
139
|
+
def initialize(token = nil, adapter = :net_http)
|
|
140
|
+
@token = token
|
|
141
|
+
@conn = connection(adapter)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def get(uri)
|
|
145
|
+
@conn.get(HOST + uri) do |req|
|
|
146
|
+
default_headers.each_pair do |key, value|
|
|
147
|
+
req.headers[key] = value
|
|
148
|
+
end
|
|
149
|
+
req.params['token'] = CGI.escape(token) if token
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
private
|
|
154
|
+
|
|
155
|
+
attr_reader :token
|
|
156
|
+
|
|
157
|
+
def connection(adapter)
|
|
158
|
+
Faraday.new() do |conn|
|
|
159
|
+
conn.adapter(adapter)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def default_headers
|
|
164
|
+
headers = {
|
|
165
|
+
'User-Agent' => "IPinfoClient/Ruby/#{IPinfo::VERSION}",
|
|
166
|
+
'Accept' => 'application/json'
|
|
167
|
+
}
|
|
168
|
+
headers['Authorization'] = "Bearer #{CGI.escape(token)}" if token
|
|
169
|
+
headers
|
|
170
|
+
end
|
|
171
|
+
end
|
data/lib/ipinfo/version.rb
CHANGED
data/lib/ipinfo_core.rb
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ipinfo/adapter'
|
|
4
|
+
require 'ipinfo/cache/default_cache'
|
|
5
|
+
require 'ipinfo/errors'
|
|
6
|
+
require 'ipinfo/response'
|
|
7
|
+
require_relative 'ipinfo/ipAddressMatcher'
|
|
8
|
+
require_relative 'ipinfo/countriesData'
|
|
9
|
+
require 'ipaddr'
|
|
10
|
+
require 'cgi'
|
|
11
|
+
|
|
12
|
+
module IPinfoCore
|
|
13
|
+
include CountriesData
|
|
14
|
+
DEFAULT_CACHE_MAXSIZE = 4096
|
|
15
|
+
DEFAULT_CACHE_TTL = 60 * 60 * 24
|
|
16
|
+
RATE_LIMIT_MESSAGE = 'To increase your limits, please review our ' \
|
|
17
|
+
'paid plans at https://ipinfo.io/pricing'
|
|
18
|
+
# Base URL to get country flag image link.
|
|
19
|
+
# "PK" -> "https://cdn.ipinfo.io/static/images/countries-flags/PK.svg"
|
|
20
|
+
COUNTRY_FLAGS_URL = 'https://cdn.ipinfo.io/static/images/countries-flags/'
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
def create(access_token = nil, settings = {})
|
|
24
|
+
IPinfo::IPinfoCore.new(access_token, settings)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class IPinfo::IPinfoCore
|
|
30
|
+
include IPinfoCore
|
|
31
|
+
attr_accessor :access_token, :countries, :httpc
|
|
32
|
+
|
|
33
|
+
def initialize(access_token = nil, settings = {})
|
|
34
|
+
@access_token = access_token
|
|
35
|
+
@httpc = IPinfo::AdapterCore.new(access_token, httpc || :net_http)
|
|
36
|
+
|
|
37
|
+
maxsize = settings.fetch('maxsize', DEFAULT_CACHE_MAXSIZE)
|
|
38
|
+
ttl = settings.fetch('ttl', DEFAULT_CACHE_TTL)
|
|
39
|
+
@cache = settings.fetch('cache', IPinfo::DefaultCache.new(ttl, maxsize))
|
|
40
|
+
@countries = settings.fetch('countries', DEFAULT_COUNTRY_LIST)
|
|
41
|
+
@eu_countries = settings.fetch('eu_countries', DEFAULT_EU_COUNTRIES_LIST)
|
|
42
|
+
@countries_flags = settings.fetch('countries_flags', DEFAULT_COUNTRIES_FLAG_LIST)
|
|
43
|
+
@countries_currencies = settings.fetch('countries_currencies', DEFAULT_COUNTRIES_CURRENCIES_LIST)
|
|
44
|
+
@continents = settings.fetch('continents', DEFAULT_CONTINENT_LIST)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def details(ip_address = nil)
|
|
48
|
+
details_base(ip_address)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def request_details(ip_address = nil)
|
|
52
|
+
if ip_address && isBogon(ip_address)
|
|
53
|
+
details = {}
|
|
54
|
+
details[:ip] = ip_address
|
|
55
|
+
details[:bogon] = true
|
|
56
|
+
details[:ip_address] = IPAddr.new(ip_address)
|
|
57
|
+
return details
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
res = @cache.get(cache_key(ip_address))
|
|
61
|
+
return res unless res.nil?
|
|
62
|
+
|
|
63
|
+
response = @httpc.get(escape_path(ip_address))
|
|
64
|
+
|
|
65
|
+
if response.status.eql?(429)
|
|
66
|
+
raise RateLimitError,
|
|
67
|
+
RATE_LIMIT_MESSAGE
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
details = JSON.parse(response.body, symbolize_names: true)
|
|
71
|
+
@cache.set(cache_key(ip_address), details)
|
|
72
|
+
details
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def details_base(ip_address)
|
|
76
|
+
details = request_details(ip_address)
|
|
77
|
+
|
|
78
|
+
# Core response has nested geo object
|
|
79
|
+
if details.key?(:geo) && details[:geo].is_a?(Hash) && details[:geo].key?(:country_code)
|
|
80
|
+
country_code = details[:geo][:country_code]
|
|
81
|
+
details[:geo][:country_name] = @countries.fetch(country_code, nil)
|
|
82
|
+
details[:geo][:is_eu] = @eu_countries.include?(country_code)
|
|
83
|
+
details[:geo][:country_flag] = @countries_flags.fetch(country_code, nil)
|
|
84
|
+
details[:geo][:country_currency] = @countries_currencies.fetch(country_code, nil)
|
|
85
|
+
details[:geo][:continent] = @continents.fetch(country_code, nil)
|
|
86
|
+
details[:geo][:country_flag_url] = "#{COUNTRY_FLAGS_URL}#{country_code}.svg"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Handle top-level country_code if present (for certain edge cases)
|
|
90
|
+
if details.key?(:country_code)
|
|
91
|
+
country_code = details[:country_code]
|
|
92
|
+
details[:country_name] = @countries.fetch(country_code, nil)
|
|
93
|
+
details[:is_eu] = @eu_countries.include?(country_code)
|
|
94
|
+
details[:country_flag] = @countries_flags.fetch(country_code, nil)
|
|
95
|
+
details[:country_currency] = @countries_currencies.fetch(country_code, nil)
|
|
96
|
+
details[:continent] = @continents.fetch(country_code, nil)
|
|
97
|
+
details[:country_flag_url] = "#{COUNTRY_FLAGS_URL}#{country_code}.svg"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
if details.key? :ip
|
|
101
|
+
details[:ip_address] =
|
|
102
|
+
IPAddr.new(details.fetch(:ip))
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
IPinfo::Response.new(details)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def isBogon(ip)
|
|
109
|
+
if ip.nil?
|
|
110
|
+
return false
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
matcher_object = IPinfo::IpAddressMatcher.new(ip)
|
|
114
|
+
matcher_object.matches
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def escape_path(ip)
|
|
118
|
+
ip ? "/#{CGI.escape(ip)}" : '/'
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def cache_key(ip)
|
|
122
|
+
"1:#{ip}"
|
|
123
|
+
end
|
|
124
|
+
end
|
data/lib/ipinfo_lite.rb
CHANGED
|
@@ -50,10 +50,10 @@ class IPinfo::IPinfoLite
|
|
|
50
50
|
|
|
51
51
|
def request_details(ip_address = nil)
|
|
52
52
|
if ip_address && ip_address != 'me' && isBogon(ip_address)
|
|
53
|
+
details = {}
|
|
53
54
|
details[:ip] = ip_address
|
|
54
55
|
details[:bogon] = true
|
|
55
56
|
details[:ip_address] = IPAddr.new(ip_address)
|
|
56
|
-
|
|
57
57
|
return details
|
|
58
58
|
end
|
|
59
59
|
|
data/lib/ipinfo_plus.rb
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ipinfo/adapter'
|
|
4
|
+
require 'ipinfo/cache/default_cache'
|
|
5
|
+
require 'ipinfo/errors'
|
|
6
|
+
require 'ipinfo/response'
|
|
7
|
+
require_relative 'ipinfo/ipAddressMatcher'
|
|
8
|
+
require_relative 'ipinfo/countriesData'
|
|
9
|
+
require 'ipaddr'
|
|
10
|
+
require 'cgi'
|
|
11
|
+
|
|
12
|
+
module IPinfoPlus
|
|
13
|
+
include CountriesData
|
|
14
|
+
DEFAULT_CACHE_MAXSIZE = 4096
|
|
15
|
+
DEFAULT_CACHE_TTL = 60 * 60 * 24
|
|
16
|
+
RATE_LIMIT_MESSAGE = 'To increase your limits, please review our ' \
|
|
17
|
+
'paid plans at https://ipinfo.io/pricing'
|
|
18
|
+
# Base URL to get country flag image link.
|
|
19
|
+
# "PK" -> "https://cdn.ipinfo.io/static/images/countries-flags/PK.svg"
|
|
20
|
+
COUNTRY_FLAGS_URL = 'https://cdn.ipinfo.io/static/images/countries-flags/'
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
def create(access_token = nil, settings = {})
|
|
24
|
+
IPinfo::IPinfoPlus.new(access_token, settings)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class IPinfo::IPinfoPlus
|
|
30
|
+
include IPinfoPlus
|
|
31
|
+
attr_accessor :access_token, :countries, :httpc
|
|
32
|
+
|
|
33
|
+
def initialize(access_token = nil, settings = {})
|
|
34
|
+
@access_token = access_token
|
|
35
|
+
@httpc = IPinfo::AdapterPlus.new(access_token, httpc || :net_http)
|
|
36
|
+
|
|
37
|
+
maxsize = settings.fetch('maxsize', DEFAULT_CACHE_MAXSIZE)
|
|
38
|
+
ttl = settings.fetch('ttl', DEFAULT_CACHE_TTL)
|
|
39
|
+
@cache = settings.fetch('cache', IPinfo::DefaultCache.new(ttl, maxsize))
|
|
40
|
+
@countries = settings.fetch('countries', DEFAULT_COUNTRY_LIST)
|
|
41
|
+
@eu_countries = settings.fetch('eu_countries', DEFAULT_EU_COUNTRIES_LIST)
|
|
42
|
+
@countries_flags = settings.fetch('countries_flags', DEFAULT_COUNTRIES_FLAG_LIST)
|
|
43
|
+
@countries_currencies = settings.fetch('countries_currencies', DEFAULT_COUNTRIES_CURRENCIES_LIST)
|
|
44
|
+
@continents = settings.fetch('continents', DEFAULT_CONTINENT_LIST)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def details(ip_address = nil)
|
|
48
|
+
details_base(ip_address)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def request_details(ip_address = nil)
|
|
52
|
+
if ip_address && isBogon(ip_address)
|
|
53
|
+
details = {}
|
|
54
|
+
details[:ip] = ip_address
|
|
55
|
+
details[:bogon] = true
|
|
56
|
+
details[:ip_address] = IPAddr.new(ip_address)
|
|
57
|
+
return details
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
res = @cache.get(cache_key(ip_address))
|
|
61
|
+
return res unless res.nil?
|
|
62
|
+
|
|
63
|
+
response = @httpc.get(escape_path(ip_address))
|
|
64
|
+
|
|
65
|
+
if response.status.eql?(429)
|
|
66
|
+
raise RateLimitError,
|
|
67
|
+
RATE_LIMIT_MESSAGE
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
details = JSON.parse(response.body, symbolize_names: true)
|
|
71
|
+
@cache.set(cache_key(ip_address), details)
|
|
72
|
+
details
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def details_base(ip_address)
|
|
76
|
+
details = request_details(ip_address)
|
|
77
|
+
|
|
78
|
+
# Plus response has nested geo object (same structure as Core)
|
|
79
|
+
if details.key?(:geo) && details[:geo].is_a?(Hash) && details[:geo].key?(:country_code)
|
|
80
|
+
country_code = details[:geo][:country_code]
|
|
81
|
+
details[:geo][:country_name] = @countries.fetch(country_code, nil)
|
|
82
|
+
details[:geo][:is_eu] = @eu_countries.include?(country_code)
|
|
83
|
+
details[:geo][:country_flag] = @countries_flags.fetch(country_code, nil)
|
|
84
|
+
details[:geo][:country_currency] = @countries_currencies.fetch(country_code, nil)
|
|
85
|
+
details[:geo][:continent] = @continents.fetch(country_code, nil)
|
|
86
|
+
details[:geo][:country_flag_url] = "#{COUNTRY_FLAGS_URL}#{country_code}.svg"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Handle top-level country_code if present (for certain edge cases)
|
|
90
|
+
if details.key?(:country_code)
|
|
91
|
+
country_code = details[:country_code]
|
|
92
|
+
details[:country_name] = @countries.fetch(country_code, nil)
|
|
93
|
+
details[:is_eu] = @eu_countries.include?(country_code)
|
|
94
|
+
details[:country_flag] = @countries_flags.fetch(country_code, nil)
|
|
95
|
+
details[:country_currency] = @countries_currencies.fetch(country_code, nil)
|
|
96
|
+
details[:continent] = @continents.fetch(country_code, nil)
|
|
97
|
+
details[:country_flag_url] = "#{COUNTRY_FLAGS_URL}#{country_code}.svg"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
if details.key? :ip
|
|
101
|
+
details[:ip_address] =
|
|
102
|
+
IPAddr.new(details.fetch(:ip))
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
IPinfo::Response.new(details)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def isBogon(ip)
|
|
109
|
+
if ip.nil?
|
|
110
|
+
return false
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
matcher_object = IPinfo::IpAddressMatcher.new(ip)
|
|
114
|
+
matcher_object.matches
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def escape_path(ip)
|
|
118
|
+
ip ? "/#{CGI.escape(ip)}" : '/'
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def cache_key(ip)
|
|
122
|
+
"1:#{ip}"
|
|
123
|
+
end
|
|
124
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: IPinfo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- IPinfo releases
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-11-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -166,7 +166,9 @@ files:
|
|
|
166
166
|
- lib/ipinfo/mod.rb
|
|
167
167
|
- lib/ipinfo/response.rb
|
|
168
168
|
- lib/ipinfo/version.rb
|
|
169
|
+
- lib/ipinfo_core.rb
|
|
169
170
|
- lib/ipinfo_lite.rb
|
|
171
|
+
- lib/ipinfo_plus.rb
|
|
170
172
|
homepage: https://ipinfo.io
|
|
171
173
|
licenses: []
|
|
172
174
|
metadata: {}
|