IPinfo 1.0.1 → 2.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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"}