maxmind-geoip2 0.0.1
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 +7 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +36 -0
- data/LICENSE-APACHE +202 -0
- data/LICENSE-MIT +17 -0
- data/README.dev.md +4 -0
- data/README.md +205 -0
- data/Rakefile +14 -0
- data/lib/maxmind/geoip2.rb +16 -0
- data/lib/maxmind/geoip2/errors.rb +7 -0
- data/lib/maxmind/geoip2/model/city.rb +60 -0
- data/lib/maxmind/geoip2/model/country.rb +55 -0
- data/lib/maxmind/geoip2/model/enterprise.rb +15 -0
- data/lib/maxmind/geoip2/reader.rb +160 -0
- data/lib/maxmind/geoip2/record/abstract.rb +21 -0
- data/lib/maxmind/geoip2/record/city.rb +33 -0
- data/lib/maxmind/geoip2/record/continent.rb +32 -0
- data/lib/maxmind/geoip2/record/country.rb +45 -0
- data/lib/maxmind/geoip2/record/location.rb +63 -0
- data/lib/maxmind/geoip2/record/place.rb +26 -0
- data/lib/maxmind/geoip2/record/postal.rb +26 -0
- data/lib/maxmind/geoip2/record/represented_country.rb +21 -0
- data/lib/maxmind/geoip2/record/subdivision.rb +44 -0
- data/lib/maxmind/geoip2/record/traits.rb +169 -0
- data/maxmind-geoip2.gemspec +22 -0
- data/test/test_model_country.rb +80 -0
- data/test/test_model_names.rb +47 -0
- data/test/test_reader.rb +381 -0
- metadata +78 -0
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rubocop/rake_task'
|
5
|
+
|
6
|
+
Rake::TestTask.new do |t|
|
7
|
+
t.libs << 'test'
|
8
|
+
end
|
9
|
+
|
10
|
+
RuboCop::RakeTask.new
|
11
|
+
|
12
|
+
desc 'Run tests and RuboCop'
|
13
|
+
task default: :test
|
14
|
+
task default: :rubocop
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'maxmind/geoip2/reader'
|
4
|
+
|
5
|
+
# rubocop:disable Style/ClassAndModuleChildren
|
6
|
+
# :nodoc: all
|
7
|
+
module MaxMind
|
8
|
+
module GeoIP2
|
9
|
+
module Record # :nodoc:
|
10
|
+
end
|
11
|
+
|
12
|
+
module Model # :nodoc:
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
# rubocop:enable Style/ClassAndModuleChildren
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'maxmind/geoip2/model/country'
|
4
|
+
require 'maxmind/geoip2/record/city'
|
5
|
+
require 'maxmind/geoip2/record/location'
|
6
|
+
require 'maxmind/geoip2/record/postal'
|
7
|
+
require 'maxmind/geoip2/record/subdivision'
|
8
|
+
|
9
|
+
module MaxMind::GeoIP2::Model
|
10
|
+
# Model class for the data returned by the GeoIP2 City web service and
|
11
|
+
# database. It is also used for GeoLite2 City lookups.
|
12
|
+
#
|
13
|
+
# The only difference between the City and Insights model classes is which
|
14
|
+
# fields in each record may be populated. See
|
15
|
+
# https://dev.maxmind.com/geoip/geoip2/web-services for more details.
|
16
|
+
#
|
17
|
+
# See Country for inherited methods.
|
18
|
+
class City < Country
|
19
|
+
# City data for the IP address. See MaxMind::GeoIP2::Record::City.
|
20
|
+
attr_reader :city
|
21
|
+
|
22
|
+
# Location data for the IP address. See MaxMind::GeoIP2::Record::Location.
|
23
|
+
attr_reader :location
|
24
|
+
|
25
|
+
# Postal data for the IP address. See MaxMind::GeoIP2::Record::Postal.
|
26
|
+
attr_reader :postal
|
27
|
+
|
28
|
+
# An array of MaxMind::GeoIP2::Record::Subdivision objects representing the
|
29
|
+
# country subdivisions for the IP address. The number and type of
|
30
|
+
# subdivisions varies by country, but a subdivision is typically a state,
|
31
|
+
# province, country, etc. Subdivisions are ordered from most general
|
32
|
+
# (largest) to most specific (smallest). If the response did not contain
|
33
|
+
# any subdivisions, this attribute will be an empty array.
|
34
|
+
attr_reader :subdivisions
|
35
|
+
|
36
|
+
def initialize(record, locales) # :nodoc:
|
37
|
+
super(record, locales)
|
38
|
+
@city = MaxMind::GeoIP2::Record::City.new(record['city'], locales)
|
39
|
+
@location = MaxMind::GeoIP2::Record::Location.new(record['location'])
|
40
|
+
@postal = MaxMind::GeoIP2::Record::Postal.new(record['postal'])
|
41
|
+
@subdivisions = create_subdivisions(record['subdivisions'], locales)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Return an object representing the most specific subdivision returned. If
|
45
|
+
# the response did not contain any subdivisions, this method returns nil.
|
46
|
+
def most_specific_subdivision
|
47
|
+
@subdivisions.last
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def create_subdivisions(subdivisions, locales)
|
53
|
+
return [] if subdivisions.nil?
|
54
|
+
|
55
|
+
subdivisions.map do |s|
|
56
|
+
MaxMind::GeoIP2::Record::Subdivision.new(s, locales)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'maxmind/geoip2/record/continent'
|
4
|
+
require 'maxmind/geoip2/record/country'
|
5
|
+
require 'maxmind/geoip2/record/represented_country'
|
6
|
+
require 'maxmind/geoip2/record/traits'
|
7
|
+
|
8
|
+
module MaxMind::GeoIP2::Model
|
9
|
+
# Model class for the data returned by the GeoIP2 Country web service and
|
10
|
+
# database. It is also used for GeoLite2 Country lookups.
|
11
|
+
class Country
|
12
|
+
# Continent data for the IP address. See MaxMind::GeoIP2::Record::Continent.
|
13
|
+
attr_reader :continent
|
14
|
+
|
15
|
+
# Country data for the IP address. This object represents the country where
|
16
|
+
# MaxMind believes the end user is located. See
|
17
|
+
# MaxMind::GeoIP2::Record::Country.
|
18
|
+
attr_reader :country
|
19
|
+
|
20
|
+
# Registered country data for the IP address. This record represents the
|
21
|
+
# country where the ISP has registered a given IP block and may differ from
|
22
|
+
# the user's country. See MaxMind::GeoIP2::Record::Country.
|
23
|
+
attr_reader :registered_country
|
24
|
+
|
25
|
+
# Represented country data for the IP address. The represented country is
|
26
|
+
# used for things like military bases. It is only present when the
|
27
|
+
# represented country differs from the country. See
|
28
|
+
# MaxMind::GeoIP2::Record::RepresentedCountry.
|
29
|
+
attr_reader :represented_country
|
30
|
+
|
31
|
+
# Data for the traits of the IP address. See
|
32
|
+
# MaxMind::GeoIP2::Record::Traits.
|
33
|
+
attr_reader :traits
|
34
|
+
|
35
|
+
def initialize(record, locales) # :nodoc:
|
36
|
+
@continent = MaxMind::GeoIP2::Record::Continent.new(
|
37
|
+
record['continent'],
|
38
|
+
locales,
|
39
|
+
)
|
40
|
+
@country = MaxMind::GeoIP2::Record::Country.new(
|
41
|
+
record['country'],
|
42
|
+
locales,
|
43
|
+
)
|
44
|
+
@registered_country = MaxMind::GeoIP2::Record::Country.new(
|
45
|
+
record['registered_country'],
|
46
|
+
locales,
|
47
|
+
)
|
48
|
+
@represented_country = MaxMind::GeoIP2::Record::RepresentedCountry.new(
|
49
|
+
record['represented_country'],
|
50
|
+
locales,
|
51
|
+
)
|
52
|
+
@traits = MaxMind::GeoIP2::Record::Traits.new(record['traits'])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'maxmind/geoip2/model/city'
|
4
|
+
|
5
|
+
module MaxMind::GeoIP2::Model
|
6
|
+
# Model class for the data returned by GeoIP2 Enterprise database lookups.
|
7
|
+
#
|
8
|
+
# The only difference between the City and Insights model classes is which
|
9
|
+
# fields in each record may be populated. See
|
10
|
+
# https://dev.maxmind.com/geoip/geoip2/web-services for more details.
|
11
|
+
#
|
12
|
+
# See City for inherited methods.
|
13
|
+
class Enterprise < City
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'maxmind/db'
|
4
|
+
require 'maxmind/geoip2/errors'
|
5
|
+
require 'maxmind/geoip2/model/city'
|
6
|
+
require 'maxmind/geoip2/model/country'
|
7
|
+
require 'maxmind/geoip2/model/enterprise'
|
8
|
+
|
9
|
+
module MaxMind::GeoIP2
|
10
|
+
# Reader is a reader for the GeoIP2/GeoLite2 database format. IP addresses
|
11
|
+
# can be looked up using the database specific methods.
|
12
|
+
#
|
13
|
+
# == Example
|
14
|
+
#
|
15
|
+
# require 'maxmind/geoip2'
|
16
|
+
#
|
17
|
+
# reader = MaxMind::GeoIP2::Reader.new('GeoIP2-Country.mmdb')
|
18
|
+
#
|
19
|
+
# record = reader.country('1.2.3.4')
|
20
|
+
# puts record.country.iso_code
|
21
|
+
#
|
22
|
+
# reader.close
|
23
|
+
class Reader
|
24
|
+
# Create a Reader for looking up IP addresses in a GeoIP2/GeoLite2 database
|
25
|
+
# file.
|
26
|
+
#
|
27
|
+
# If you're performing multiple lookups, it's most efficient to create one
|
28
|
+
# Reader and reuse it.
|
29
|
+
#
|
30
|
+
# Once created, the Reader is safe to use for lookups from multiple
|
31
|
+
# threads. It is safe to use after forking only if you use
|
32
|
+
# MaxMind::DB::MODE_MEMORY or if your version of Ruby supports IO#pread.
|
33
|
+
#
|
34
|
+
# Creating the Reader may raise an exception if initialization fails.
|
35
|
+
#
|
36
|
+
# +database+ is a path to a GeoIP2/GeoLite2 database file.
|
37
|
+
#
|
38
|
+
# +locales+ is a list of locale codes to use in the name property from most
|
39
|
+
# preferred to least preferred.
|
40
|
+
#
|
41
|
+
# +options+ is an option hash where each key is a symbol. The options
|
42
|
+
# control the behavior of the Reader.
|
43
|
+
#
|
44
|
+
# The available options are:
|
45
|
+
#
|
46
|
+
# [+:mode+] defines how to open the database. It may be one of
|
47
|
+
# MaxMind::DB::MODE_AUTO, MaxMind::DB::MODE_FILE, or
|
48
|
+
# MaxMind::DB::MODE_MEMORY. If you don't provide one, the Reader uses
|
49
|
+
# MaxMind::DB::MODE_AUTO. Refer to the definition of those constants
|
50
|
+
# in MaxMind::DB for an explanation of their meaning.
|
51
|
+
#
|
52
|
+
# === Exceptions
|
53
|
+
#
|
54
|
+
# Raises a MaxMind::DB::InvalidDatabaseError if the database is corrupt or
|
55
|
+
# invalid. It can raise other exceptions, such as ArgumentError, if other
|
56
|
+
# errors occur.
|
57
|
+
def initialize(database, locales = ['en'], options = {})
|
58
|
+
@reader = MaxMind::DB.new(database, options)
|
59
|
+
@type = @reader.metadata.database_type
|
60
|
+
locales = ['en'] if locales.empty?
|
61
|
+
@locales = locales
|
62
|
+
end
|
63
|
+
|
64
|
+
# Look up the +ip_address+ in the database and returns a
|
65
|
+
# MaxMind::GeoIP2::Model::City object.
|
66
|
+
#
|
67
|
+
# +ip_address+ is a string in the standard notation. It may be IPv4 or
|
68
|
+
# IPv6.
|
69
|
+
#
|
70
|
+
# === Exceptions
|
71
|
+
#
|
72
|
+
# Raises an ArgumentError if used against a non-City database or if you
|
73
|
+
# attempt to look up an IPv6 address in an IPv4 only database.
|
74
|
+
#
|
75
|
+
# Raises an AddressNotFoundError if +ip_address+ is not found in the
|
76
|
+
# database.
|
77
|
+
#
|
78
|
+
# Raises a MaxMind::DB::InvalidDatabaseError if the database appears
|
79
|
+
# corrupt.
|
80
|
+
def city(ip_address)
|
81
|
+
model_for(Model::City, 'city', 'City', ip_address)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Look up the +ip_address+ in the database and returns a
|
85
|
+
# MaxMind::GeoIP2::Model::Country object.
|
86
|
+
#
|
87
|
+
# +ip_address+ is a string in the standard notation. It may be IPv4 or
|
88
|
+
# IPv6.
|
89
|
+
#
|
90
|
+
# === Exceptions
|
91
|
+
#
|
92
|
+
# Raises an ArgumentError if used against a non-Country database or if you
|
93
|
+
# attempt to look up an IPv6 address in an IPv4 only database.
|
94
|
+
#
|
95
|
+
# Raises an AddressNotFoundError if +ip_address+ is not found in the
|
96
|
+
# database.
|
97
|
+
#
|
98
|
+
# Raises a MaxMind::DB::InvalidDatabaseError if the database appears
|
99
|
+
# corrupt.
|
100
|
+
def country(ip_address)
|
101
|
+
model_for(Model::Country, 'country', 'Country', ip_address)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Look up the +ip_address+ in the database and returns a
|
105
|
+
# MaxMind::GeoIP2::Model::Enterprise object.
|
106
|
+
#
|
107
|
+
# +ip_address+ is a string in the standard notation. It may be IPv4 or
|
108
|
+
# IPv6.
|
109
|
+
#
|
110
|
+
# === Exceptions
|
111
|
+
#
|
112
|
+
# Raises an ArgumentError if used against a non-Enterprise database or if
|
113
|
+
# you attempt to look up an IPv6 address in an IPv4 only database.
|
114
|
+
#
|
115
|
+
# Raises an AddressNotFoundError if +ip_address+ is not found in the
|
116
|
+
# database.
|
117
|
+
#
|
118
|
+
# Raises a MaxMind::DB::InvalidDatabaseError if the database appears
|
119
|
+
# corrupt.
|
120
|
+
def enterprise(ip_address)
|
121
|
+
model_for(Model::Enterprise, 'enterprise', 'Enterprise', ip_address)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Return the metadata associated with the database as a
|
125
|
+
# MaxMind::DB::Metadata object.
|
126
|
+
def metadata
|
127
|
+
@reader.metadata
|
128
|
+
end
|
129
|
+
|
130
|
+
# Close the Reader and return resources to the system.
|
131
|
+
#
|
132
|
+
# There is no useful return value. #close raises an exception if there is
|
133
|
+
# an error.
|
134
|
+
def close
|
135
|
+
@reader.close
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def model_for(model_class, method, type, ip_address)
|
141
|
+
if !@type.include?(type)
|
142
|
+
raise ArgumentError,
|
143
|
+
"The #{method} method cannot be used with the #{@type} database."
|
144
|
+
end
|
145
|
+
|
146
|
+
record, prefix_length = @reader.get_with_prefix_length(ip_address)
|
147
|
+
|
148
|
+
if record.nil?
|
149
|
+
raise AddressNotFoundError,
|
150
|
+
"The address #{ip_address} is not in the database."
|
151
|
+
end
|
152
|
+
|
153
|
+
record['traits'] = {} if !record.key?('traits')
|
154
|
+
record['traits']['ip_address'] = ip_address
|
155
|
+
record['traits']['prefix_length'] = prefix_length
|
156
|
+
|
157
|
+
model_class.new(record, @locales)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MaxMind::GeoIP2::Record
|
4
|
+
class Abstract # :nodoc:
|
5
|
+
def initialize(record)
|
6
|
+
@record = record
|
7
|
+
end
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def get(key)
|
12
|
+
if @record.nil? || !@record.key?(key)
|
13
|
+
return false if key.start_with?('is_')
|
14
|
+
|
15
|
+
return nil
|
16
|
+
end
|
17
|
+
|
18
|
+
@record[key]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'maxmind/geoip2/record/place'
|
4
|
+
|
5
|
+
module MaxMind::GeoIP2::Record
|
6
|
+
# City-level data associated with an IP address.
|
7
|
+
#
|
8
|
+
# This record is returned by all location services and databases besides
|
9
|
+
# Country.
|
10
|
+
#
|
11
|
+
# See Place for inherited methods.
|
12
|
+
class City < Place
|
13
|
+
# A value from 0-100 indicating MaxMind's confidence that the city is
|
14
|
+
# correct. This attribute is only available from the Insights service and
|
15
|
+
# the GeoIP2 Enterprise database. Integer but may be nil.
|
16
|
+
def confidence
|
17
|
+
get('confidence')
|
18
|
+
end
|
19
|
+
|
20
|
+
# The GeoName ID for the city. This attribute is returned by all location
|
21
|
+
# services and databases. Integer but may be nil.
|
22
|
+
def geoname_id
|
23
|
+
get('geoname_id')
|
24
|
+
end
|
25
|
+
|
26
|
+
# A Hash where the keys are locale codes (Strings) and the values are names
|
27
|
+
# (Strings). This attribute is returned by all location services and
|
28
|
+
# databases. Hash but may be nil.
|
29
|
+
def names
|
30
|
+
get('names')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'maxmind/geoip2/record/place'
|
4
|
+
|
5
|
+
module MaxMind::GeoIP2::Record
|
6
|
+
# Contains data for the continent record associated with an IP address.
|
7
|
+
#
|
8
|
+
# This record is returned by all location services and databases.
|
9
|
+
#
|
10
|
+
# See Place for inherited methods.
|
11
|
+
class Continent < Place
|
12
|
+
# A two character continent code like "NA" (North America) or "OC"
|
13
|
+
# (Oceania). This attribute is returned by all location services and
|
14
|
+
# databases. String but may be nil.
|
15
|
+
def code
|
16
|
+
get('code')
|
17
|
+
end
|
18
|
+
|
19
|
+
# The GeoName ID for the continent. This attribute is returned by all
|
20
|
+
# location services and databases. String but may be nil.
|
21
|
+
def geoname_id
|
22
|
+
get('geoname_id')
|
23
|
+
end
|
24
|
+
|
25
|
+
# A Hash where the keys are locale codes (Strings) and the values are names
|
26
|
+
# (Strings). This attribute is returned by all location services and
|
27
|
+
# databases. Hash but may be nil.
|
28
|
+
def names
|
29
|
+
get('names')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'maxmind/geoip2/record/place'
|
4
|
+
|
5
|
+
module MaxMind::GeoIP2::Record
|
6
|
+
# Contains data for the country record associated with an IP address.
|
7
|
+
#
|
8
|
+
# This record is returned by all location services and databases.
|
9
|
+
#
|
10
|
+
# See Place for inherited methods.
|
11
|
+
class Country < Place
|
12
|
+
# A value from 0-100 indicating MaxMind's confidence that the country is
|
13
|
+
# correct. This attribute is only available from the Insights service and
|
14
|
+
# the GeoIP2 Enterprise database. Integer but may be nil.
|
15
|
+
def confidence
|
16
|
+
get('confidence')
|
17
|
+
end
|
18
|
+
|
19
|
+
# The GeoName ID for the country. This attribute is returned by all
|
20
|
+
# location services and databases. Integer but may be nil.
|
21
|
+
def geoname_id
|
22
|
+
get('geoname_id')
|
23
|
+
end
|
24
|
+
|
25
|
+
# This is true if the country is a member state of the European Union. This
|
26
|
+
# attribute is returned by all location services and databases. Boolean.
|
27
|
+
def in_european_union?
|
28
|
+
get('is_in_european_union')
|
29
|
+
end
|
30
|
+
|
31
|
+
# The two-character ISO 3166-1 alpha code for the country. See
|
32
|
+
# https://en.wikipedia.org/wiki/ISO_3166-1. This attribute is returned by
|
33
|
+
# all location services and databases. String but may be nil.
|
34
|
+
def iso_code
|
35
|
+
get('iso_code')
|
36
|
+
end
|
37
|
+
|
38
|
+
# A Hash where the keys are locale codes (Strings) and the values are names
|
39
|
+
# (Strings). This attribute is returned by all location services and
|
40
|
+
# databases. Hash but may be nil.
|
41
|
+
def names
|
42
|
+
get('names')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|