trackdown 0.1.0
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 +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +141 -0
- data/Rakefile +4 -0
- data/lib/generators/trackdown/install_generator.rb +25 -0
- data/lib/generators/trackdown/templates/trackdown.rb +21 -0
- data/lib/generators/trackdown/templates/trackdown_database_refresh_job.rb +7 -0
- data/lib/trackdown/configuration.rb +49 -0
- data/lib/trackdown/database_updater.rb +57 -0
- data/lib/trackdown/error.rb +5 -0
- data/lib/trackdown/ip_locator.rb +84 -0
- data/lib/trackdown/ip_validator.rb +24 -0
- data/lib/trackdown/location_result.rb +36 -0
- data/lib/trackdown/version.rb +5 -0
- data/lib/trackdown.rb +43 -0
- data/sig/trackdown.rbs +4 -0
- metadata +152 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6bef9cf45c5eb0f1cebf958c00d8b655d0840b07fe3ae3bca3732e0bdd25e2f8
|
4
|
+
data.tar.gz: ac99be87d20b6795d7ce156bc9ae50af70e0b4506fa61c00851f5c1abb690e39
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e69d703884469e3880eb06472182e00d356884a92089074a9e4ea916b8709d22bb34de22c8d5d37e16d8aada028099f96e22a2bc2a88c6aa10610a99f04c208b
|
7
|
+
data.tar.gz: 18c3f1641bcec2facfbefc038d715f434e8a2f9bf5e53b1d83d85ed12d38fa008460bbe936cf47654de2686f6bdb2412fc6a90d2836107e573783e8a9fec435a
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2024 Javi R
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
# π `trackdown` - Ruby gem to geolocate IPs (MaxMind BYOK)
|
2
|
+
|
3
|
+
`trackdown` is a Ruby gem that easily allows you to geolocate IP addresses. It's a simple, convenient wrapper on top of MaxMind. Just bring your own MaxMind keys, and you're good to go. It keeps your MaxMind database updated regularly, and it offers a handy API for Rails applications to fetch country, city, and emoji flag information for any IP address.
|
4
|
+
|
5
|
+
Given an IP, it gives you the corresponding:
|
6
|
+
- πΊοΈ Country (two-letter country code + country name)
|
7
|
+
- π City
|
8
|
+
- πΊπΈ Emoji flag of the country
|
9
|
+
|
10
|
+
`trackdown` is BYOK (Bring Your Own Key) β you'll need your own MaxMind keys for it to work. It's your responsibility to make sure your app complies with the license for the MaxMind database you're using. Get a MaxMind account and license key at [MaxMind](https://www.maxmind.com/).
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem 'trackdown'
|
18
|
+
```
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
```bash
|
23
|
+
bundle install
|
24
|
+
```
|
25
|
+
|
26
|
+
## Setup
|
27
|
+
|
28
|
+
First, run the installation generator:
|
29
|
+
|
30
|
+
```bash
|
31
|
+
rails generate trackdown:install
|
32
|
+
```
|
33
|
+
|
34
|
+
This will create an initializer file at `config/initializers/trackdown.rb`. Open this file and add your MaxMind license key and account ID:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
Trackdown.configure do |config|
|
38
|
+
# Tip: do not write your plaintext keys in the code, use Rails.application.credentials instead
|
39
|
+
config.maxmind_account_id = 'your_account_id_here'
|
40
|
+
config.maxmind_license_key = 'your_license_key_here'
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
> [!TIP]
|
45
|
+
> To get your MaxMind account ID and license key, you need to create an account at [MaxMind](https://www.maxmind.com/) and get a license key.
|
46
|
+
|
47
|
+
You can also configure the path where the MaxMind database will be stored. By default, it will be stored at `db/GeoLite2-City.mmdb`:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
config.database_path = Rails.root.join('db', 'GeoLite2-City.mmdb').to_s
|
51
|
+
```
|
52
|
+
|
53
|
+
The generator also creates a `TrackdownDatabaseRefreshJob` job for regularly updating the MaxMind database. You can just get a database the first time and just keep using it, but the information will get outdated and some IPs will become stale or inaccurate.
|
54
|
+
|
55
|
+
To keep your IP geolocation accurate, you need to make sure the `TrackdownDatabaseRefreshJob` runs regularly. How you do that, exactly, depends on the queueing system you're using.
|
56
|
+
|
57
|
+
If you're using `solid_queue` (the Rails 8 default), you can easily add it to your schedule in the `config/recurring.yml` file like this:
|
58
|
+
```yaml
|
59
|
+
production:
|
60
|
+
refresh_maxmind_database:
|
61
|
+
class: TrackdownDatabaseRefreshJob
|
62
|
+
queue: default
|
63
|
+
schedule: every day at 4am US/Pacific
|
64
|
+
```
|
65
|
+
|
66
|
+
After setting everything up, you can run the following command to update the MaxMind database / get the first fresh copy of it:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
Trackdown.update_database
|
70
|
+
```
|
71
|
+
|
72
|
+
## Usage
|
73
|
+
|
74
|
+
To geolocate an IP address:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
Trackdown.locate('8.8.8.8').country
|
78
|
+
# => 'United States'
|
79
|
+
```
|
80
|
+
|
81
|
+
You can also do things like:
|
82
|
+
```ruby
|
83
|
+
Trackdown.locate('8.8.8.8').emoji
|
84
|
+
# => 'πΊπΈ'
|
85
|
+
```
|
86
|
+
|
87
|
+
In fact, there are a few methods you can use:
|
88
|
+
```ruby
|
89
|
+
result = Trackdown.locate('8.8.8.8')
|
90
|
+
|
91
|
+
result.country_code # => 'US'
|
92
|
+
result.country_name # => 'United States'
|
93
|
+
result.country # => 'United States' (alias for country_name)
|
94
|
+
result.country_info # => # A big hash of information about the country, from the `countries` gem
|
95
|
+
result.city # => 'Mountain View'
|
96
|
+
result.flag_emoji # => 'πΊπΈ'
|
97
|
+
result.emoji # => 'πΊπΈ' (alias for flag_emoji)
|
98
|
+
result.country_flag # => 'πΊπΈ' (alias for flag_emoji)
|
99
|
+
```
|
100
|
+
|
101
|
+
For `country_info` we're leveraging the [`countries`](https://github.com/countries/countries) gem, so you get a lot of information about the country, like the continent, the region, the languages spoken, the currency, and more:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
result.country_info.alpha3 # => "USA"
|
105
|
+
result.country_info.currency_code # => "USD"
|
106
|
+
result.country_info.continent # => 'North America'
|
107
|
+
result.country_info.nationality # => 'American'
|
108
|
+
result.country_info.iso_long_name # => 'The United States of America'
|
109
|
+
```
|
110
|
+
|
111
|
+
If you prefer, you can also get all the information as a hash:
|
112
|
+
```ruby
|
113
|
+
result.to_h
|
114
|
+
# => {
|
115
|
+
# country_code: 'US',
|
116
|
+
# country_name: 'United States',
|
117
|
+
# city: 'Mountain View',
|
118
|
+
# flag_emoji: 'πΊπΈ',
|
119
|
+
# country_info: { ... }
|
120
|
+
# }
|
121
|
+
```
|
122
|
+
|
123
|
+
To manually update the MaxMind IP database:
|
124
|
+
```ruby
|
125
|
+
Trackdown.update_database
|
126
|
+
```
|
127
|
+
|
128
|
+
|
129
|
+
## Development
|
130
|
+
|
131
|
+
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.
|
132
|
+
|
133
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
134
|
+
|
135
|
+
## Contributing
|
136
|
+
|
137
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/rameerez/trackdown. Our code of conduct is: just be nice and make your mom proud of what you do and post online.
|
138
|
+
|
139
|
+
## License
|
140
|
+
|
141
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Trackdown
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path('templates', __dir__)
|
5
|
+
|
6
|
+
def create_initializer
|
7
|
+
template 'trackdown.rb', 'config/initializers/trackdown.rb'
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_database_refresh_job
|
11
|
+
template 'trackdown_database_refresh_job.rb', 'app/jobs/trackdown_database_refresh_job.rb'
|
12
|
+
end
|
13
|
+
|
14
|
+
def display_post_install_message
|
15
|
+
say "\tThe `trackdown` gem has been successfully installed!", :green
|
16
|
+
say "\nTo complete the setup:"
|
17
|
+
say " 1. Configure your MaxMind credentials in `config/initializers/trackdown.rb`"
|
18
|
+
say " 2. Run 'Trackdown.update_database' to get a fresh MaxMind IP database."
|
19
|
+
say " 3. Make sure you configure your queueing system to run the TrackdownDatabaseRefreshJob regularly so the IP database is updated regularly."
|
20
|
+
say "\nEnjoy `trackdown`!", :green
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Trackdown.configure do |config|
|
4
|
+
# Required: Your MaxMind credentials
|
5
|
+
config.maxmind_account_id = Rails.application.credentials.dig(:maxmind, :account_id)
|
6
|
+
config.maxmind_license_key = Rails.application.credentials.dig(:maxmind, :license_key)
|
7
|
+
|
8
|
+
# Optional: Configure database location (defaults to db/GeoLite2-City.mmdb)
|
9
|
+
# config.database_path = Rails.root.join('db', 'GeoLite2-City.mmdb').to_s
|
10
|
+
|
11
|
+
# Optional: Configure timeouts and pooling (defaults shown)
|
12
|
+
# config.timeout = 3 # Timeout for individual lookups
|
13
|
+
# config.pool_size = 5 # Size of the connection pool
|
14
|
+
# config.pool_timeout = 3 # Timeout when waiting for a connection from the pool
|
15
|
+
|
16
|
+
# Optional: Configure memory mode (defaults to MODE_MEMORY)
|
17
|
+
# config.memory_mode = MaxMind::DB::MODE_FILE # Use MODE_FILE to reduce memory usage
|
18
|
+
|
19
|
+
# Optional: Configure IP validation (defaults to true)
|
20
|
+
# config.reject_private_ips = true # Reject private/local IP addresses
|
21
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trackdown
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :maxmind_license_key, :maxmind_account_id, :database_path,
|
6
|
+
:timeout, :pool_size, :pool_timeout, :memory_mode,
|
7
|
+
:reject_private_ips
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@maxmind_license_key = nil
|
11
|
+
@maxmind_account_id = nil
|
12
|
+
@database_path = defined?(Rails) ? Rails.root.join('db', 'GeoLite2-City.mmdb').to_s : 'db/GeoLite2-City.mmdb'
|
13
|
+
@timeout = 3 # seconds
|
14
|
+
@pool_size = 5
|
15
|
+
@pool_timeout = 3 # seconds
|
16
|
+
@memory_mode = MaxMind::DB::MODE_MEMORY
|
17
|
+
@reject_private_ips = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def validate!
|
21
|
+
missing = []
|
22
|
+
missing << 'maxmind_license_key' if maxmind_license_key.nil?
|
23
|
+
missing << 'maxmind_account_id' if maxmind_account_id.nil?
|
24
|
+
|
25
|
+
raise Error, "Missing required configuration: #{missing.join(', ')} β Please set these in your config/initializers/trackdown.rb initializer." unless missing.empty?
|
26
|
+
|
27
|
+
validate_paths!
|
28
|
+
validate_timeouts!
|
29
|
+
end
|
30
|
+
|
31
|
+
def reject_private_ips?
|
32
|
+
@reject_private_ips
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def validate_paths!
|
38
|
+
unless database_path && !database_path.empty?
|
39
|
+
raise Error, "database_path cannot be empty"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def validate_timeouts!
|
44
|
+
raise Error, "timeout must be positive" unless timeout.positive?
|
45
|
+
raise Error, "pool_timeout must be positive" unless pool_timeout.positive?
|
46
|
+
raise Error, "pool_size must be positive" unless pool_size.positive?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'zlib'
|
3
|
+
require 'rubygems/package'
|
4
|
+
|
5
|
+
module Trackdown
|
6
|
+
class DatabaseUpdater
|
7
|
+
DOWNLOAD_URL = "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=%{license_key}&suffix=tar.gz"
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def update
|
11
|
+
download_url = DOWNLOAD_URL % { license_key: Trackdown.configuration.maxmind_license_key }
|
12
|
+
|
13
|
+
options = {
|
14
|
+
http_basic_authentication: [
|
15
|
+
Trackdown.configuration.maxmind_account_id.to_s,
|
16
|
+
Trackdown.configuration.maxmind_license_key.to_s
|
17
|
+
],
|
18
|
+
ssl_verify_mode: OpenSSL::SSL::VERIFY_PEER
|
19
|
+
}
|
20
|
+
|
21
|
+
URI.open(download_url, **options) do |remote_file|
|
22
|
+
Zlib::GzipReader.wrap(remote_file) do |gz|
|
23
|
+
Gem::Package::TarReader.new(gz) do |tar|
|
24
|
+
tar.each do |entry|
|
25
|
+
if entry.full_name.end_with?('.mmdb')
|
26
|
+
FileUtils.mkdir_p(File.dirname(Trackdown.configuration.database_path))
|
27
|
+
|
28
|
+
File.open(Trackdown.configuration.database_path, 'wb') do |file|
|
29
|
+
file.write(entry.read)
|
30
|
+
end
|
31
|
+
break
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Rails.logger.info("MaxMind database updated successfully") if defined?(Rails)
|
39
|
+
true
|
40
|
+
rescue OpenURI::HTTPError => e
|
41
|
+
message = case e.message
|
42
|
+
when /401/
|
43
|
+
"Authentication failed. Please check your MaxMind account ID and license key."
|
44
|
+
when /403/
|
45
|
+
"Access forbidden. Your MaxMind license may not have access to this database."
|
46
|
+
else
|
47
|
+
"HTTP Error: #{e.message}"
|
48
|
+
end
|
49
|
+
Rails.logger.error("Error updating MaxMind database: #{message}") if defined?(Rails)
|
50
|
+
raise Error, message
|
51
|
+
rescue => e
|
52
|
+
Rails.logger.error("Error updating MaxMind database: #{e.message}") if defined?(Rails)
|
53
|
+
raise Error, "Failed to update database: #{e.message}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'maxmind/db'
|
4
|
+
require 'connection_pool'
|
5
|
+
require_relative 'location_result'
|
6
|
+
require_relative 'ip_validator'
|
7
|
+
|
8
|
+
module Trackdown
|
9
|
+
class IpLocator
|
10
|
+
class TimeoutError < Trackdown::Error; end
|
11
|
+
class DatabaseError < Trackdown::Error; end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def locate(ip)
|
15
|
+
IpValidator.validate!(ip)
|
16
|
+
|
17
|
+
if Trackdown.configuration.reject_private_ips? && IpValidator.private_ip?(ip)
|
18
|
+
raise IpValidator::InvalidIpError, "Private IP addresses are not allowed"
|
19
|
+
end
|
20
|
+
|
21
|
+
record = fetch_record(ip)
|
22
|
+
return LocationResult.new(nil, 'Unknown', 'Unknown', 'π³οΈ') if record.nil?
|
23
|
+
|
24
|
+
country_code = extract_country_code(record)
|
25
|
+
country_name = extract_country_name(record)
|
26
|
+
city = extract_city(record)
|
27
|
+
flag_emoji = get_emoji_flag(country_code)
|
28
|
+
|
29
|
+
LocationResult.new(country_code, country_name, city, flag_emoji)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def fetch_record(ip)
|
35
|
+
Trackdown.ensure_database_exists!
|
36
|
+
|
37
|
+
Timeout.timeout(Trackdown.configuration.timeout) do
|
38
|
+
reader_pool.with do |reader|
|
39
|
+
reader.get(ip)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
rescue Timeout::Error
|
43
|
+
raise TimeoutError, "MaxMind database lookup timed out after #{Trackdown.configuration.timeout} seconds"
|
44
|
+
rescue Trackdown::Error => e
|
45
|
+
raise e
|
46
|
+
rescue StandardError => e
|
47
|
+
Rails.logger.error("Error fetching IP data: #{e.message}") if defined?(Rails)
|
48
|
+
raise DatabaseError, "Database error: #{e.message}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def reader_pool
|
52
|
+
@reader_pool ||= ConnectionPool.new(
|
53
|
+
size: Trackdown.configuration.pool_size,
|
54
|
+
timeout: Trackdown.configuration.pool_timeout
|
55
|
+
) do
|
56
|
+
MaxMind::DB.new(
|
57
|
+
Trackdown.configuration.database_path,
|
58
|
+
mode: Trackdown.configuration.memory_mode
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def extract_country_code(record)
|
64
|
+
record&.dig('country', 'iso_code')
|
65
|
+
end
|
66
|
+
|
67
|
+
def extract_country_name(record)
|
68
|
+
record&.dig('country', 'names', 'en') ||
|
69
|
+
(record&.dig('country', 'names')&.values&.first) ||
|
70
|
+
'Unknown'
|
71
|
+
end
|
72
|
+
|
73
|
+
def extract_city(record)
|
74
|
+
record&.dig('city', 'names', 'en') ||
|
75
|
+
(record&.dig('city', 'names')&.values&.first) ||
|
76
|
+
'Unknown'
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_emoji_flag(country_code)
|
80
|
+
country_code ? country_code.tr('A-Z', "\u{1F1E6}-\u{1F1FF}") : "π³οΈ"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ipaddr'
|
4
|
+
|
5
|
+
module Trackdown
|
6
|
+
class IpValidator
|
7
|
+
class InvalidIpError < Trackdown::Error; end
|
8
|
+
|
9
|
+
def self.validate!(ip)
|
10
|
+
return if ip.nil?
|
11
|
+
|
12
|
+
begin
|
13
|
+
IPAddr.new(ip.to_s)
|
14
|
+
rescue IPAddr::InvalidAddressError
|
15
|
+
raise InvalidIpError, "Invalid IP address format: #{ip}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.private_ip?(ip)
|
20
|
+
addr = IPAddr.new(ip.to_s)
|
21
|
+
addr.private? || addr.loopback?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'countries'
|
4
|
+
|
5
|
+
module Trackdown
|
6
|
+
class LocationResult
|
7
|
+
attr_reader :country_code, :country_name, :city, :flag_emoji
|
8
|
+
|
9
|
+
def initialize(country_code, country_name, city, flag_emoji)
|
10
|
+
@country_code = country_code
|
11
|
+
@country_name = country_name
|
12
|
+
@city = city
|
13
|
+
@flag_emoji = flag_emoji
|
14
|
+
end
|
15
|
+
|
16
|
+
alias_method :country, :country_name
|
17
|
+
alias_method :emoji, :flag_emoji
|
18
|
+
alias_method :emoji_flag, :flag_emoji
|
19
|
+
alias_method :country_flag, :flag_emoji
|
20
|
+
|
21
|
+
def country_info
|
22
|
+
return nil unless country_code
|
23
|
+
ISO3166::Country.new(country_code)
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_h
|
27
|
+
{
|
28
|
+
country_code: @country_code,
|
29
|
+
country_name: @country_name,
|
30
|
+
city: @city,
|
31
|
+
flag_emoji: @flag_emoji,
|
32
|
+
country_info: country_info&.data || {}
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/trackdown.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "trackdown/error"
|
4
|
+
require_relative "trackdown/version"
|
5
|
+
require_relative "trackdown/configuration"
|
6
|
+
require_relative "trackdown/ip_validator"
|
7
|
+
require_relative "trackdown/ip_locator"
|
8
|
+
require_relative "trackdown/database_updater"
|
9
|
+
require_relative "trackdown/location_result"
|
10
|
+
|
11
|
+
module Trackdown
|
12
|
+
class << self
|
13
|
+
attr_writer :configuration
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.configuration
|
17
|
+
@configuration ||= Configuration.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.configure
|
21
|
+
yield(configuration)
|
22
|
+
configuration.validate!
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.locate(ip)
|
26
|
+
ensure_database_exists!
|
27
|
+
IpLocator.locate(ip)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.update_database
|
31
|
+
DatabaseUpdater.update
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.database_exists?
|
35
|
+
File.exist?(configuration.database_path)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.ensure_database_exists!
|
39
|
+
unless database_exists?
|
40
|
+
raise Error, "MaxMind database not found. Please set your MaxMind keys in config/initializers/trackdown.rb as described in the `trackdown` gem README, and then run Trackdown.update_database to download the MaxMind IP geolocation database."
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/sig/trackdown.rbs
ADDED
metadata
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: trackdown
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- rameerez
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-10-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: maxmind-db
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: connection_pool
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.4'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.4'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: countries
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '7.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '7.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '13.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '13.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.21'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.21'
|
97
|
+
description: Trackdown is a Ruby gem that easily allows you to geolocate IP addresses.
|
98
|
+
It's a simple, convenient wrapper on top of the MaxMind database. Plug your MaxMind
|
99
|
+
license key and you're good to go. It keeps your MaxMind database updated regularly,
|
100
|
+
and it offers a handy API for Rails applications to fetch country, city, and emoji
|
101
|
+
flag information for any IP address.
|
102
|
+
email:
|
103
|
+
- rubygems@rameerez.com
|
104
|
+
executables: []
|
105
|
+
extensions: []
|
106
|
+
extra_rdoc_files: []
|
107
|
+
files:
|
108
|
+
- CHANGELOG.md
|
109
|
+
- LICENSE.txt
|
110
|
+
- README.md
|
111
|
+
- Rakefile
|
112
|
+
- lib/generators/trackdown/install_generator.rb
|
113
|
+
- lib/generators/trackdown/templates/trackdown.rb
|
114
|
+
- lib/generators/trackdown/templates/trackdown_database_refresh_job.rb
|
115
|
+
- lib/trackdown.rb
|
116
|
+
- lib/trackdown/configuration.rb
|
117
|
+
- lib/trackdown/database_updater.rb
|
118
|
+
- lib/trackdown/error.rb
|
119
|
+
- lib/trackdown/ip_locator.rb
|
120
|
+
- lib/trackdown/ip_validator.rb
|
121
|
+
- lib/trackdown/location_result.rb
|
122
|
+
- lib/trackdown/version.rb
|
123
|
+
- sig/trackdown.rbs
|
124
|
+
homepage: https://github.com/rameerez/trackdown
|
125
|
+
licenses:
|
126
|
+
- MIT
|
127
|
+
metadata:
|
128
|
+
allowed_push_host: https://rubygems.org
|
129
|
+
homepage_uri: https://github.com/rameerez/trackdown
|
130
|
+
source_code_uri: https://github.com/rameerez/trackdown
|
131
|
+
changelog_uri: https://github.com/rameerez/trackdown/blob/main/CHANGELOG.md
|
132
|
+
post_install_message:
|
133
|
+
rdoc_options: []
|
134
|
+
require_paths:
|
135
|
+
- lib
|
136
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: 3.0.0
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
requirements: []
|
147
|
+
rubygems_version: 3.5.16
|
148
|
+
signing_key:
|
149
|
+
specification_version: 4
|
150
|
+
summary: Get country, city, and emoji flag information for IP addresses using a MaxMind
|
151
|
+
database
|
152
|
+
test_files: []
|