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.
@@ -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,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MaxMind::GeoIP2
4
+ # An AddressNotFoundError means the IP address was not found in the database.
5
+ class AddressNotFoundError < RuntimeError
6
+ end
7
+ end
@@ -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