IPinfo 1.0.1 → 2.2.4

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.
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'resolv'
4
+ require 'ipaddr'
5
+
6
+ class IPinfo::IpAddressMatcher
7
+ attr_accessor :required_address
8
+
9
+ @@bogon_list = [
10
+ "0.0.0.0/8",
11
+ "10.0.0.0/8",
12
+ "100.64.0.0/10",
13
+ "127.0.0.0/8",
14
+ "169.254.0.0/16",
15
+ "172.16.0.0/12",
16
+ "192.0.0.0/24",
17
+ "192.0.2.0/24",
18
+ "192.168.0.0/16",
19
+ "198.18.0.0/15",
20
+ "198.51.100.0/24",
21
+ "203.0.113.0/24",
22
+ "224.0.0.0/4",
23
+ "240.0.0.0/4",
24
+ "255.255.255.255/32",
25
+ "::/128",
26
+ "::1/128",
27
+ "::ffff:0:0/96",
28
+ "::/96",
29
+ "100::/64",
30
+ "2001:10::/28",
31
+ "2001:db8::/32",
32
+ "fc00::/7",
33
+ "fe80::/10",
34
+ "fec0::/10",
35
+ "ff00::/8",
36
+ "2002::/24",
37
+ "2002:a00::/24",
38
+ "2002:7f00::/24",
39
+ "2002:a9fe::/32",
40
+ "2002:ac10::/28",
41
+ "2002:c000::/40",
42
+ "2002:c000:200::/40",
43
+ "2002:c0a8::/32",
44
+ "2002:c612::/31",
45
+ "2002:c633:6400::/40",
46
+ "2002:cb00:7100::/40",
47
+ "2002:e000::/20",
48
+ "2002:f000::/20",
49
+ "2002:ffff:ffff::/48",
50
+ "2001::/40",
51
+ "2001:0:a00::/40",
52
+ "2001:0:7f00::/40",
53
+ "2001:0:a9fe::/48",
54
+ "2001:0:ac10::/44",
55
+ "2001:0:c000::/56",
56
+ "2001:0:c000:200::/56",
57
+ "2001:0:c0a8::/48",
58
+ "2001:0:c612::/47",
59
+ "2001:0:c633:6400::/56",
60
+ "2001:0:cb00:7100::/56",
61
+ "2001:0:e000::/36",
62
+ "2001:0:f000::/36",
63
+ "2001:0:ffff:ffff::/64"
64
+ ]
65
+
66
+ def initialize(ip)
67
+ if !ip.index('/').nil? and ip.index('/') > 0
68
+ addr_mask = ip.split('/')
69
+ ip = addr_mask[0]
70
+ end
71
+
72
+ @required_address = parseAddress(ip)
73
+ end
74
+
75
+ def parseAddress(ip)
76
+ begin
77
+ Resolv.getaddress ip
78
+ rescue Resolv::ResolvError => e
79
+ pp e
80
+ end
81
+ end
82
+
83
+ def matches
84
+ for bogon in @@bogon_list do
85
+ if bogon.include? required_address
86
+ return true
87
+ end
88
+ end
89
+
90
+ false
91
+ end
92
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IPinfo
4
- VERSION = '1.0.1'
4
+ VERSION = '2.2.4'
5
5
  end
data/lib/ipinfo.rb CHANGED
@@ -8,14 +8,18 @@ require 'ipinfo/errors'
8
8
  require 'ipinfo/response'
9
9
  require 'ipinfo/version'
10
10
  require 'json'
11
+ require_relative 'ipinfo/ipAddressMatcher'
12
+ require_relative 'ipinfo/countriesData'
11
13
 
12
14
  module IPinfo
15
+ include CountriesData
13
16
  DEFAULT_CACHE_MAXSIZE = 4096
14
17
  DEFAULT_CACHE_TTL = 60 * 60 * 24
15
- DEFAULT_COUNTRY_FILE = File.join(File.dirname(__FILE__),
16
- 'ipinfo/countries.json')
17
18
  RATE_LIMIT_MESSAGE = 'To increase your limits, please review our ' \
18
19
  'paid plans at https://ipinfo.io/pricing'
20
+ # Base URL to get country flag image link.
21
+ # "PK" -> "https://cdn.ipinfo.io/static/images/countries-flags/PK.svg"
22
+ COUNTRY_FLAGS_URL = "https://cdn.ipinfo.io/static/images/countries-flags/"
19
23
 
20
24
  class << self
21
25
  def create(access_token = nil, settings = {})
@@ -30,43 +34,102 @@ class IPinfo::IPinfo
30
34
 
31
35
  def initialize(access_token = nil, settings = {})
32
36
  @access_token = access_token
33
- @httpc = prepare_http_client(settings.fetch('http_client', nil))
37
+ prepare_http_client(settings.fetch('http_client', nil))
34
38
 
35
39
  maxsize = settings.fetch('maxsize', DEFAULT_CACHE_MAXSIZE)
36
40
  ttl = settings.fetch('ttl', DEFAULT_CACHE_TTL)
37
41
  @cache = settings.fetch('cache', DefaultCache.new(ttl, maxsize))
38
- @countries = prepare_countries(settings.fetch('countries',
39
- DEFAULT_COUNTRY_FILE))
42
+ @countries = settings.fetch('countries', DEFAULT_COUNTRY_LIST)
43
+ @eu_countries = settings.fetch('eu_countries', DEFAULT_EU_COUNTRIES_LIST)
44
+ @countries_flags = settings.fetch('countries_flags', DEFAULT_COUNTRIES_FLAG_LIST)
45
+ @countries_currencies = settings.fetch('countries_currencies', DEFAULT_COUNTRIES_CURRENCIES_LIST)
46
+ @continents = settings.fetch('continents', DEFAULT_CONTINENT_LIST)
40
47
  end
41
48
 
42
49
  def details(ip_address = nil)
43
- details = request_details(ip_address)
44
- if details.key? :country
45
- details[:country_name] =
46
- @countries.fetch(details.fetch(:country), nil)
50
+ details_base(ip_address, :v4)
51
+ end
52
+
53
+ def details_v6(ip_address = nil)
54
+ details_base(ip_address, :v6)
55
+ end
56
+
57
+ def get_map_url(ips)
58
+ if !ips.kind_of?(Array)
59
+ return JSON.generate({:error => 'Invalid input. Array required!'})
60
+ end
61
+ if ips.length > 500000
62
+ return JSON.generate({:error => 'No more than 500,000 ips allowed!'})
47
63
  end
48
64
 
49
- if details.key? :ip
50
- details[:ip_address] =
51
- IPAddr.new(details.fetch(:ip))
65
+ json_ips = JSON.generate({:ips => ips})
66
+ res = @httpc.post('/tools/map', json_ips)
67
+
68
+ obj = JSON.parse(res.body)
69
+ obj['reportUrl']
70
+ end
71
+
72
+ def batch_requests(url_array, api_token)
73
+ result = Hash.new
74
+ lookup_ips = []
75
+
76
+ url_array.each { |url|
77
+ ip = @cache.get(cache_key(url))
78
+
79
+ unless ip.nil?
80
+ result.store(url, ip)
81
+ else
82
+ lookup_ips << url
83
+ end
84
+ }
85
+
86
+ if lookup_ips.empty?
87
+ return result
52
88
  end
53
89
 
54
- if details.key? :loc
55
- loc = details.fetch(:loc).split(',')
56
- details[:latitude] = loc[0]
57
- details[:longitude] = loc[1]
90
+ begin
91
+ lookup_ips.each_slice(1000){ |ips|
92
+ json_arr = JSON.generate(lookup_ips)
93
+ res = @httpc.post("/batch?token=#{api_token}", json_arr, 5)
94
+
95
+ raise StandardError, "Request Quota Exceeded" if res.status == 429
96
+
97
+ data = JSON.parse(res.body)
98
+ data.each { |key, val|
99
+ @cache.set(cache_key(key), val)
100
+ }
101
+
102
+ result.merge!(data)
103
+ }
104
+
105
+ rescue StandardError => e
106
+ return e.message
58
107
  end
59
108
 
60
- Response.new(details)
109
+ result
61
110
  end
62
111
 
63
112
  protected
64
113
 
65
- def request_details(ip_address = nil)
66
- res = @cache.get(ip_address)
114
+ def prepare_http_client(httpc = nil)
115
+ @httpc = Adapter.new(access_token, httpc || :net_http)
116
+ end
117
+
118
+ private
119
+
120
+ def request_details(ip_address = nil, host_type)
121
+ if isBogon(ip_address)
122
+ details[:ip] = ip_address
123
+ details[:bogon] = true
124
+ details[:ip_address] = IPAddr.new(ip_address)
125
+
126
+ return details
127
+ end
128
+
129
+ res = @cache.get(cache_key(ip_address))
67
130
  return res unless res.nil?
68
131
 
69
- response = @httpc.get(escape_path(ip_address))
132
+ response = @httpc.get(escape_path(ip_address), host_type)
70
133
 
71
134
  if response.status.eql?(429)
72
135
  raise RateLimitError,
@@ -74,26 +137,54 @@ class IPinfo::IPinfo
74
137
  end
75
138
 
76
139
  details = JSON.parse(response.body, symbolize_names: true)
77
- @cache.set(ip_address, details)
140
+ @cache.set(cache_key(ip_address), details)
78
141
  details
79
142
  end
80
143
 
81
- def prepare_http_client(httpc = nil)
82
- @httpc = if httpc
83
- Adapter.new(access_token, httpc)
84
- else
85
- Adapter.new(access_token)
86
- end
87
- end
144
+ def details_base(ip_address, host_type)
145
+ details = request_details(ip_address, host_type)
146
+ if details.key? :country
147
+ details[:country_name] =
148
+ @countries.fetch(details.fetch(:country), nil)
149
+ details[:is_eu] =
150
+ @eu_countries.include?(details.fetch(:country))
151
+ details[:country_flag] =
152
+ @countries_flags.fetch(details.fetch(:country), nil)
153
+ details[:country_currency] =
154
+ @countries_currencies.fetch(details.fetch(:country), nil)
155
+ details[:continent] =
156
+ @continents.fetch(details.fetch(:country), nil)
157
+ details[:country_flag_url] = COUNTRY_FLAGS_URL + details.fetch(:country) + ".svg"
158
+ end
88
159
 
89
- def prepare_countries(filename)
90
- file = File.read(filename)
91
- JSON.parse(file)
160
+ if details.key? :ip
161
+ details[:ip_address] =
162
+ IPAddr.new(details.fetch(:ip))
163
+ end
164
+
165
+ if details.key? :loc
166
+ loc = details.fetch(:loc).split(',')
167
+ details[:latitude] = loc[0]
168
+ details[:longitude] = loc[1]
169
+ end
170
+
171
+ Response.new(details)
92
172
  end
93
173
 
94
- private
174
+ def isBogon(ip)
175
+ if ip.nil?
176
+ return false
177
+ end
178
+
179
+ matcher_object = IpAddressMatcher.new(ip)
180
+ matcher_object.matches
181
+ end
95
182
 
96
183
  def escape_path(ip)
97
184
  ip ? "/#{CGI.escape(ip)}" : '/'
98
185
  end
186
+
187
+ def cache_key(ip)
188
+ "1:#{ip}"
189
+ end
99
190
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: IPinfo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 2.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stanislav K, James Timmins
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2021-01-05 00:00:00.000000000 Z
12
+ date: 2024-09-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
@@ -17,14 +17,98 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: '1.0'
20
+ version: '2.0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '2.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: async-http-faraday
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: faraday-net_http_persistent
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '2.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '2.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: faraday-typhoeus
58
+ requirement: !ruby/object:Gem::Requirement
24
59
  requirements:
25
60
  - - "~>"
26
61
  - !ruby/object:Gem::Version
27
62
  version: '1.0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: faraday-patron
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '2.0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '2.0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: faraday-httpclient
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '2.0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '2.0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: faraday-excon
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '2.1'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '2.1'
28
112
  - !ruby/object:Gem::Dependency
29
113
  name: json
30
114
  requirement: !ruby/object:Gem::Requirement
@@ -62,10 +146,11 @@ extensions: []
62
146
  extra_rdoc_files: []
63
147
  files:
64
148
  - ".editorconfig"
149
+ - ".github/workflows/cd_rubygems.yaml"
150
+ - ".github/workflows/unittest.yaml"
65
151
  - ".gitignore"
66
152
  - ".rubocop.yml"
67
153
  - ".ruby-version"
68
- - ".travis.yml"
69
154
  - Gemfile
70
155
  - LICENSE
71
156
  - README.md
@@ -77,8 +162,9 @@ files:
77
162
  - lib/ipinfo/adapter.rb
78
163
  - lib/ipinfo/cache/cache_interface.rb
79
164
  - lib/ipinfo/cache/default_cache.rb
80
- - lib/ipinfo/countries.json
165
+ - lib/ipinfo/countriesData.rb
81
166
  - lib/ipinfo/errors.rb
167
+ - lib/ipinfo/ipAddressMatcher.rb
82
168
  - lib/ipinfo/mod.rb
83
169
  - lib/ipinfo/response.rb
84
170
  - lib/ipinfo/version.rb
@@ -100,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
186
  - !ruby/object:Gem::Version
101
187
  version: '0'
102
188
  requirements: []
103
- rubygems_version: 3.1.4
189
+ rubygems_version: 3.4.10
104
190
  signing_key:
105
191
  specification_version: 4
106
192
  summary: This is a ruby wrapper for http://ipinfo.io.
data/.travis.yml DELETED
@@ -1,11 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- cache: bundler
4
-
5
- rvm:
6
- - 2.5
7
- - 2.6
8
- - 2.7
9
-
10
- before_install:
11
- - gem install bundler
@@ -1 +0,0 @@
1
- {"BD": "Bangladesh", "BE": "Belgium", "BF": "Burkina Faso", "BG": "Bulgaria", "BA": "Bosnia and Herzegovina", "BB": "Barbados", "WF": "Wallis and Futuna", "BL": "Saint Barthelemy", "BM": "Bermuda", "BN": "Brunei", "BO": "Bolivia", "BH": "Bahrain", "BI": "Burundi", "BJ": "Benin", "BT": "Bhutan", "JM": "Jamaica", "BV": "Bouvet Island", "BW": "Botswana", "WS": "Samoa", "BQ": "Bonaire, Saint Eustatius and Saba ", "BR": "Brazil", "BS": "Bahamas", "JE": "Jersey", "BY": "Belarus", "BZ": "Belize", "RU": "Russia", "RW": "Rwanda", "RS": "Serbia", "TL": "East Timor", "RE": "Reunion", "TM": "Turkmenistan", "TJ": "Tajikistan", "RO": "Romania", "TK": "Tokelau", "GW": "Guinea-Bissau", "GU": "Guam", "GT": "Guatemala", "GS": "South Georgia and the South Sandwich Islands", "GR": "Greece", "GQ": "Equatorial Guinea", "GP": "Guadeloupe", "JP": "Japan", "GY": "Guyana", "GG": "Guernsey", "GF": "French Guiana", "GE": "Georgia", "GD": "Grenada", "GB": "United Kingdom", "GA": "Gabon", "SV": "El Salvador", "GN": "Guinea", "GM": "Gambia", "GL": "Greenland", "GI": "Gibraltar", "GH": "Ghana", "OM": "Oman", "TN": "Tunisia", "JO": "Jordan", "HR": "Croatia", "HT": "Haiti", "HU": "Hungary", "HK": "Hong Kong", "HN": "Honduras", "HM": "Heard Island and McDonald Islands", "VE": "Venezuela", "PR": "Puerto Rico", "PS": "Palestinian Territory", "PW": "Palau", "PT": "Portugal", "SJ": "Svalbard and Jan Mayen", "PY": "Paraguay", "IQ": "Iraq", "PA": "Panama", "PF": "French Polynesia", "PG": "Papua New Guinea", "PE": "Peru", "PK": "Pakistan", "PH": "Philippines", "PN": "Pitcairn", "PL": "Poland", "PM": "Saint Pierre and Miquelon", "ZM": "Zambia", "EH": "Western Sahara", "EE": "Estonia", "EG": "Egypt", "ZA": "South Africa", "EC": "Ecuador", "IT": "Italy", "VN": "Vietnam", "SB": "Solomon Islands", "ET": "Ethiopia", "SO": "Somalia", "ZW": "Zimbabwe", "SA": "Saudi Arabia", "ES": "Spain", "ER": "Eritrea", "ME": "Montenegro", "MD": "Moldova", "MG": "Madagascar", "MF": "Saint Martin", "MA": "Morocco", "MC": "Monaco", "UZ": "Uzbekistan", "MM": "Myanmar", "ML": "Mali", "MO": "Macao", "MN": "Mongolia", "MH": "Marshall Islands", "MK": "Macedonia", "MU": "Mauritius", "MT": "Malta", "MW": "Malawi", "MV": "Maldives", "MQ": "Martinique", "MP": "Northern Mariana Islands", "MS": "Montserrat", "MR": "Mauritania", "IM": "Isle of Man", "UG": "Uganda", "TZ": "Tanzania", "MY": "Malaysia", "MX": "Mexico", "IL": "Israel", "FR": "France", "IO": "British Indian Ocean Territory", "SH": "Saint Helena", "FI": "Finland", "FJ": "Fiji", "FK": "Falkland Islands", "FM": "Micronesia", "FO": "Faroe Islands", "NI": "Nicaragua", "NL": "Netherlands", "NO": "Norway", "NA": "Namibia", "VU": "Vanuatu", "NC": "New Caledonia", "NE": "Niger", "NF": "Norfolk Island", "NG": "Nigeria", "NZ": "New Zealand", "NP": "Nepal", "NR": "Nauru", "NU": "Niue", "CK": "Cook Islands", "XK": "Kosovo", "CI": "Ivory Coast", "CH": "Switzerland", "CO": "Colombia", "CN": "China", "CM": "Cameroon", "CL": "Chile", "CC": "Cocos Islands", "CA": "Canada", "CG": "Republic of the Congo", "CF": "Central African Republic", "CD": "Democratic Republic of the Congo", "CZ": "Czech Republic", "CY": "Cyprus", "CX": "Christmas Island", "CR": "Costa Rica", "CW": "Curacao", "CV": "Cape Verde", "CU": "Cuba", "SZ": "Swaziland", "SY": "Syria", "SX": "Sint Maarten", "KG": "Kyrgyzstan", "KE": "Kenya", "SS": "South Sudan", "SR": "Suriname", "KI": "Kiribati", "KH": "Cambodia", "KN": "Saint Kitts and Nevis", "KM": "Comoros", "ST": "Sao Tome and Principe", "SK": "Slovakia", "KR": "South Korea", "SI": "Slovenia", "KP": "North Korea", "KW": "Kuwait", "SN": "Senegal", "SM": "San Marino", "SL": "Sierra Leone", "SC": "Seychelles", "KZ": "Kazakhstan", "KY": "Cayman Islands", "SG": "Singapore", "SE": "Sweden", "SD": "Sudan", "DO": "Dominican Republic", "DM": "Dominica", "DJ": "Djibouti", "DK": "Denmark", "VG": "British Virgin Islands", "DE": "Germany", "YE": "Yemen", "DZ": "Algeria", "US": "United States", "UY": "Uruguay", "YT": "Mayotte", "UM": "United States Minor Outlying Islands", "LB": "Lebanon", "LC": "Saint Lucia", "LA": "Laos", "TV": "Tuvalu", "TW": "Taiwan", "TT": "Trinidad and Tobago", "TR": "Turkey", "LK": "Sri Lanka", "LI": "Liechtenstein", "LV": "Latvia", "TO": "Tonga", "LT": "Lithuania", "LU": "Luxembourg", "LR": "Liberia", "LS": "Lesotho", "TH": "Thailand", "TF": "French Southern Territories", "TG": "Togo", "TD": "Chad", "TC": "Turks and Caicos Islands", "LY": "Libya", "VA": "Vatican", "VC": "Saint Vincent and the Grenadines", "AE": "United Arab Emirates", "AD": "Andorra", "AG": "Antigua and Barbuda", "AF": "Afghanistan", "AI": "Anguilla", "VI": "U.S. Virgin Islands", "IS": "Iceland", "IR": "Iran", "AM": "Armenia", "AL": "Albania", "AO": "Angola", "AQ": "Antarctica", "AS": "American Samoa", "AR": "Argentina", "AU": "Australia", "AT": "Austria", "AW": "Aruba", "IN": "India", "AX": "Aland Islands", "AZ": "Azerbaijan", "IE": "Ireland", "ID": "Indonesia", "UA": "Ukraine", "QA": "Qatar", "MZ": "Mozambique"}