ip_lookup 1.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/README.md +73 -0
- data/Rakefile +8 -0
- data/lib/ip-lookup.rb +62 -0
- data/lib/ip_lookup/db.rb +92 -0
- data/lib/ip_lookup/defaults.rb +8 -0
- data/lib/ip_lookup/errors.rb +5 -0
- data/lib/ip_lookup/version.rb +5 -0
- data/lib/rubygems_plugin.rb +9 -0
- metadata +184 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3fc773650faa6ffc425dca036e1e2ca80bacafd51548eb16754720ca8c5b07ec
|
4
|
+
data.tar.gz: b260b88a05a4366df81d10a5d44271c8d7c11d0650c3997d76e242d64003f3f2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4b2c9138cde92e92ef7e795a3845c5e8a4fb097b7a236d83085cd00ef9270be86d32adc780c4b538d27594736dcd80aff82c2b04f07de46cc76ad01ef6daab6e
|
7
|
+
data.tar.gz: 3dec5779bc48e845223983eacc66050abc6e5e37e6d78d7f6c6f94ec616fbc932982555c777e6ff9e7c6fe6fb699ef2b040f6c482bbe1459ce97bc7680900ed2
|
data/README.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# IPLookup
|
2
|
+
|
3
|
+
IPLookup uses [GeoIP2 MaxMind DB](http://maxmind.github.io/MaxMind-DB/) to lookup the country, timezone, coordinates and subdivision for a given ip address.
|
4
|
+
|
5
|
+
## Dependencies
|
6
|
+
|
7
|
+
* Uses the gem [maxminddb](https://github.com/yhirose/maxminddb) as a database reader.
|
8
|
+
* Uses the gem [TZInfo](https://github.com/tzinfo/tzinfo) for timezone lookup.
|
9
|
+
* Uses the gem [Zlib](https://github.com/ruby/zlib) to decompress database file.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
gem 'ip_lookup'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install ip_lookup
|
24
|
+
|
25
|
+
### Configuration
|
26
|
+
|
27
|
+
Before using the gem the db file needs to be downloaded / updated.
|
28
|
+
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
# download / update database
|
32
|
+
IPLookup.DB.update update_period: 30, update_uri: "http://path_to_database_GeoLite2-City.mmdb.gz"
|
33
|
+
```
|
34
|
+
|
35
|
+
- default update_period (in days): 30
|
36
|
+
- default update_uri: http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz
|
37
|
+
|
38
|
+
*NOTE: The gem provides a RubyGems post-install hook to download / update the db.*
|
39
|
+
|
40
|
+
### Usage
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
ip_lookup = IPLookup.new "213.61.214.178", silent_exceptions: false
|
44
|
+
|
45
|
+
ip_lookup.country
|
46
|
+
# => "de"
|
47
|
+
|
48
|
+
ip_lookup.timezone
|
49
|
+
# => "Europe/Berlin"
|
50
|
+
|
51
|
+
ip_lookup.coordinates
|
52
|
+
# => [51.2993, 9.491]
|
53
|
+
|
54
|
+
ip_lookup.subdivision
|
55
|
+
# => "be"
|
56
|
+
```
|
57
|
+
|
58
|
+
*Defaults:*
|
59
|
+
- silent_exceptions: false
|
60
|
+
|
61
|
+
## Development
|
62
|
+
|
63
|
+
After checking out the repo, run bin/setup to install dependencies. Then, run `rake spec` to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
|
64
|
+
|
65
|
+
To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.
|
66
|
+
|
67
|
+
## License
|
68
|
+
|
69
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
70
|
+
|
71
|
+
## Code of Conduct
|
72
|
+
|
73
|
+
Everyone interacting in the IPLookup project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/blinkist/ip-lookup/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
data/lib/ip-lookup.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "maxminddb"
|
4
|
+
require "tzinfo"
|
5
|
+
|
6
|
+
require_relative "ip_lookup/db"
|
7
|
+
require_relative "ip_lookup/defaults"
|
8
|
+
require_relative "ip_lookup/errors"
|
9
|
+
|
10
|
+
class IPLookup
|
11
|
+
attr_reader :result
|
12
|
+
attr_reader :silent_exceptions
|
13
|
+
|
14
|
+
def initialize(ip_address, silent_exceptions: false)
|
15
|
+
@silent_exceptions = silent_exceptions
|
16
|
+
@result = DB.new(silent_exceptions).lookup(ip_address)
|
17
|
+
end
|
18
|
+
|
19
|
+
def country
|
20
|
+
error_handler(DEFAULT_COUNTRY) do
|
21
|
+
iso_code = result.country.iso_code
|
22
|
+
iso_code ? iso_code.downcase : DEFAULT_COUNTRY
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def timezone
|
27
|
+
error_handler(DEFAULT_TIMEZONE) do
|
28
|
+
timezone = result.location.time_zone
|
29
|
+
|
30
|
+
timezone ||= timezone_for result.country.iso_code if result.country.iso_code
|
31
|
+
|
32
|
+
timezone || DEFAULT_TIMEZONE
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def coordinates
|
37
|
+
error_handler(DEFAULT_COORDINATES) do
|
38
|
+
[result.location.latitude, result.location.longitude]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def subdivision
|
43
|
+
error_handler(DEFAULT_SUBDIVISION) do
|
44
|
+
result.subdivisions.any? ? result.subdivisions.first.iso_code.downcase : DEFAULT_SUBDIVISION
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def timezone_for(iso_code)
|
51
|
+
tz = TZInfo::Country.get iso_code
|
52
|
+
tz.zone_identifiers.first if tz.zone_identifiers.any?
|
53
|
+
end
|
54
|
+
|
55
|
+
def error_handler(default)
|
56
|
+
result&.found? ? yield : default
|
57
|
+
rescue IPAddr::InvalidAddressError, IPAddr::AddressFamilyError
|
58
|
+
raise e unless silent_exceptions
|
59
|
+
|
60
|
+
default
|
61
|
+
end
|
62
|
+
end
|
data/lib/ip_lookup/db.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "zlib"
|
4
|
+
require "net/http"
|
5
|
+
|
6
|
+
class IPLookup
|
7
|
+
class DB
|
8
|
+
DEFAULT_UPDATE_PERIOD_IN_DAYS = 30
|
9
|
+
DEFAULT_UPDATE_URI = "https://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz"
|
10
|
+
|
11
|
+
attr_reader :silent_exceptions
|
12
|
+
|
13
|
+
def initialize(silent_exceptions)
|
14
|
+
@silent_exceptions = silent_exceptions
|
15
|
+
end
|
16
|
+
|
17
|
+
def lookup(ip_address)
|
18
|
+
db.lookup ip_address
|
19
|
+
rescue Errno::ENOENT
|
20
|
+
raise DBFileNotFoundError, "Couldn't find DB file. Please update DB before using lookup." unless silent_exceptions
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.mutex
|
24
|
+
@mutex ||= Mutex.new
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def db
|
30
|
+
self.class.mutex.synchronize do
|
31
|
+
@db ||= begin
|
32
|
+
MaxMindDB.new self.class.db_path
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class << self
|
38
|
+
def update(update_period: DEFAULT_UPDATE_PERIOD_IN_DAYS, update_uri: DEFAULT_UPDATE_URI)
|
39
|
+
return unless update_db? update_period
|
40
|
+
|
41
|
+
save_db fetch_db(update_uri)
|
42
|
+
end
|
43
|
+
|
44
|
+
def fetch_db(update_uri)
|
45
|
+
uri = URI(update_uri)
|
46
|
+
|
47
|
+
response = Net::HTTP.get(uri)
|
48
|
+
|
49
|
+
sio_response = StringIO.new(response)
|
50
|
+
gz = Zlib::GzipReader.new(sio_response)
|
51
|
+
gz.read
|
52
|
+
end
|
53
|
+
|
54
|
+
def save_db(result)
|
55
|
+
File.open(db_path, 'w') do |file|
|
56
|
+
flock(file) do |f|
|
57
|
+
f.write(result)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def flock(file)
|
63
|
+
# return and don't update db if file is locked, because db is already been updated
|
64
|
+
return unless file.flock(File::LOCK_EX | File::LOCK_NB)
|
65
|
+
|
66
|
+
if file.flock(File::LOCK_EX)
|
67
|
+
begin
|
68
|
+
yield file
|
69
|
+
ensure
|
70
|
+
file.flock(File::LOCK_UN)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def update_db?(update_period)
|
76
|
+
!db_exists? || (update_period >= 0 && db_age > update_period)
|
77
|
+
end
|
78
|
+
|
79
|
+
def db_exists?
|
80
|
+
File.file? db_path
|
81
|
+
end
|
82
|
+
|
83
|
+
def db_age
|
84
|
+
(Time.now - File.mtime(db_path)) / (24 * 60 * 60)
|
85
|
+
end
|
86
|
+
|
87
|
+
def db_path
|
88
|
+
File.join(Gem.loaded_specs["ip_lookup"].full_gem_path, "/support/geolite-city.mmdb")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
metadata
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ip_lookup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ole Richter
|
8
|
+
- Tomek Poderski
|
9
|
+
- Sebastian Schleicher
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2018-08-13 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: maxminddb
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - ">="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '0'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: tzinfo
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
type: :runtime
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: zlib
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
type: :runtime
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: bundler
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '1.16'
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - "~>"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '1.16'
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: byebug
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: json
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
type: :development
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
name: rake
|
101
|
+
requirement: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - "~>"
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '10.0'
|
106
|
+
type: :development
|
107
|
+
prerelease: false
|
108
|
+
version_requirements: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - "~>"
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '10.0'
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: rspec
|
115
|
+
requirement: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - "~>"
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '3.0'
|
120
|
+
type: :development
|
121
|
+
prerelease: false
|
122
|
+
version_requirements: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - "~>"
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '3.0'
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
name: rubocop
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
description: IPLookup uses GeoIP2 MaxMind DB to lookup the country, timezone, coordinates
|
142
|
+
and locale for ip adresses.
|
143
|
+
email:
|
144
|
+
- ole@blinkist.com
|
145
|
+
- tomek@blinkist.com
|
146
|
+
- sj@blinkist.com
|
147
|
+
executables: []
|
148
|
+
extensions: []
|
149
|
+
extra_rdoc_files: []
|
150
|
+
files:
|
151
|
+
- README.md
|
152
|
+
- Rakefile
|
153
|
+
- lib/ip-lookup.rb
|
154
|
+
- lib/ip_lookup/db.rb
|
155
|
+
- lib/ip_lookup/defaults.rb
|
156
|
+
- lib/ip_lookup/errors.rb
|
157
|
+
- lib/ip_lookup/version.rb
|
158
|
+
- lib/rubygems_plugin.rb
|
159
|
+
homepage: https://github.com/blinkist/ip-lookup
|
160
|
+
licenses:
|
161
|
+
- MIT
|
162
|
+
metadata: {}
|
163
|
+
post_install_message:
|
164
|
+
rdoc_options: []
|
165
|
+
require_paths:
|
166
|
+
- lib
|
167
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
168
|
+
requirements:
|
169
|
+
- - ">="
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '0'
|
172
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '0'
|
177
|
+
requirements: []
|
178
|
+
rubyforge_project:
|
179
|
+
rubygems_version: 2.7.7
|
180
|
+
signing_key:
|
181
|
+
specification_version: 4
|
182
|
+
summary: IPLookup uses GeoIP2 MaxMind DB to lookup the country, timezone, coordinates
|
183
|
+
and locale for ip adresses.
|
184
|
+
test_files: []
|