pax_global_header00006660000000000000000000000064135116266230014517gustar00rootroot0000000000000052 comment=85f63a43f6915bd8ef4fd07b844a00a17be94027 ruby-maxminddb-0.1.22/000077500000000000000000000000001351162662300145235ustar00rootroot00000000000000ruby-maxminddb-0.1.22/.gitignore000066400000000000000000000000551351162662300165130ustar00rootroot00000000000000spec/cache/*.mmdb *.swp .ruby-* Gemfile.lock ruby-maxminddb-0.1.22/.rspec000066400000000000000000000000371351162662300156400ustar00rootroot00000000000000--color --format documentation ruby-maxminddb-0.1.22/.travis.yml000066400000000000000000000003401351162662300166310ustar00rootroot00000000000000language: ruby rvm: - 1.9.3 - 2.0 - 2.1 - 2.2 - 2.3 - 2.4.0 - 2.5.1 - 2.6.0-preview2 - jruby-19mode script: bundle exec rake before_install: - gem update bundler cache: directories: - spec/cache ruby-maxminddb-0.1.22/CHANGELOG.md000066400000000000000000000020161351162662300163330ustar00rootroot00000000000000# Changelog ### 0.1.22 (September 15, 2018) - Result includes 'network' ### 0.1.21 (July 20, 2018) - Make the low-memory file reader opt-in ### 0.1.20 (July 9, 2018) - Add local_ip_alias ### 0.1.19 (June 22, 2018) - Implement a faster default reader ### 0.1.18 (June 18, 2018) - Backward Compatible Client Initialize ### 0.1.17 (June 9, 2018) - Allow the database file reader to be overridden. - increase coverage for IPv6 and EU tests ### 0.1.16 (May 22, 2018) - Adds is_in_european_union feature ### 0.1.15 (December 18, 2017) - Implement #most_specific method for result subdivisions #31 ### 0.1.14 (July 26, 2017) - Expose accuracy_radius in Location data #29 ### 0.1.13 (June 13, 2017) - Expose database metadata #27 ### 0.1.12 (January 11, 2017) - Removed Fixnum and Bignum deprecation warnings (in ruby 2.4) - Update Travis - Fix failing test ### 0.1.11 (March 7, 2016) - Fixed problem with 32bit record data ### 0.1.10 (February 25, 2016) - Performance tweaks *** *For older releases, see commit log.* ruby-maxminddb-0.1.22/Gemfile000066400000000000000000000001361351162662300160160ustar00rootroot00000000000000source 'https://rubygems.org' # Specify your gem's dependencies in maxminddb.gemspec gemspec ruby-maxminddb-0.1.22/LICENSE.txt000066400000000000000000000020501351162662300163430ustar00rootroot00000000000000Copyright (c) 2014 yhirose MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ruby-maxminddb-0.1.22/README.md000066400000000000000000000122041351162662300160010ustar00rootroot00000000000000# maxminddb Pure Ruby [GeoIP2 MaxMind DB](http://maxmind.github.io/MaxMind-DB/) reader, which doesn't require [libmaxminddb](https://github.com/maxmind/libmaxminddb). You can find more information about the GeoIP2 database [here](http://dev.maxmind.com/geoip/geoip2/downloadable/). [![Gem Version](https://badge.fury.io/rb/maxminddb.svg)](http://badge.fury.io/rb/maxminddb) [![Build Status](https://travis-ci.org/yhirose/maxminddb.svg?branch=master)](https://travis-ci.org/yhirose/maxminddb) [![Code Climate](https://codeclimate.com/github/yhirose/maxminddb.png)](https://codeclimate.com/github/yhirose/maxminddb) ## Installation Add this line to your application's Gemfile: ```ruby gem 'maxminddb' ``` And then execute: ```sh $ bundle ``` Or install it yourself as: ```sh $ gem install maxminddb ``` ## Usage ```ruby db = MaxMindDB.new('./GeoLite2-City.mmdb') ret = db.lookup('74.125.225.224') ret.found? # => true ret.country.name # => 'United States' ret.country.name('zh-CN') # => '美国' ret.country.iso_code # => 'US' ret.city.name(:fr) # => 'Mountain View' ret.subdivisions.most_specific.name # => 'California' ret.location.latitude # => -122.0574 ret.to_hash # => {"city"=>{"geoname_id"=>5375480, "names"=>{"de"=>"Mountain View", "en"=>"Mountain View", "fr"=>"Mountain View", "ja"=>"マウンテンビュー", "ru"=>"Маунтин-Вью", "zh-CN"=>"芒廷维尤"}}, "continent"=>{"code"=>"NA", "geoname_id"=>6255149, "names"=>{"de"=>"Nordamerika", "en"=>"North America", "es"=>"Norteamérica", "fr"=>"Amérique du Nord", "ja"=>"北アメリカ", "pt-BR"=>"América do Norte", "ru"=>"Северная Америка", "zh-CN"=>"北美洲"}}, "country"=>{"geoname_id"=>6252001, "iso_code"=>"US", "names"=>{"de"=>"USA", "en"=>"United States", "es"=>"Estados Unidos", "fr"=>"États-Unis", "ja"=>"アメリカ合衆国", "pt-BR"=>"Estados Unidos", "ru"=>"Сша", "zh-CN"=>"美国"}}, "location"=>{"latitude"=>37.419200000000004, "longitude"=>-122.0574, "metro_code"=>807, "time_zone"=>"America/Los_Angeles"}, "postal"=>{"code"=>"94043"}, "registered_country"=>{"geoname_id"=>6252001, "iso_code"=>"US", "names"=>{"de"=>"USA", "en"=>"United States", "es"=>"Estados Unidos", "fr"=>"États-Unis", "ja"=>"アメリカ合衆国", "pt-BR"=>"Estados Unidos", "ru"=>"Сша", "zh-CN"=>"美国"}}, "subdivisions"=>[{"geoname_id"=>5332921, "iso_code"=>"CA", "names"=>{"de"=>"Kalifornien", "en"=>"California", "es"=>"California", "fr"=>"Californie", "ja"=>"カリフォルニア州", "pt-BR"=>"Califórnia", "ru"=>"Калифорния", "zh-CN"=>"加利福尼亚州"}}]} ``` Even if no result could be found, you can ask for the attributes without guarding for nil: ```ruby db = MaxMindDB.new('./GeoLite2-City.mmdb') ret = db.lookup('127.0.0.1') ret.found? # => false ret.country.name # => nil ret.to_hash # => {} ``` For testing or other purposes, you might wish to treat localhost IP addresses as some other address - an external one. You can do this by assigning the desired external IP address to the attribute local_ip_alias: ```ruby db = MaxMindDB.new('./GeoLite2-City.mmdb') ret = db.local_ip_alias = '74.125.225.224' ret = db.lookup('127.0.0.1') ret.found? # => true ret.country.name # => 'United States' ret.to_hash.empty? # => false ``` It's also possible to access the database metadata. ```ruby db = MaxMindDB.new('./GeoLite2-City.mmdb') db.metadata['build_epoch'] # => 1493762948 db.metadata # => {"binary_format_major_version"=>2, "binary_format_minor_version"=>0, "build_epoch"=>1493762948, "database_type"=>"GeoLite2-City", "description"=>{"en"=>"GeoLite2 City database"}, "ip_version"=>6, "languages"=>["de", "en", "es", "fr", "ja", "pt-BR", "ru", "zh-CN"], "node_count"=>3678850, "record_size"=>28} ``` ### Regarding thread safety A MaxMindDB instance doesn't do any write operation after it is created. So we can consider it as an immutable object which is 'thread-safe'. ### JSON web server on Docker maxminddb-docker: https://github.com/samnissen/maxminddb-docker ### File reading strategies By default, `MaxMinDB.new` will read the entire database into memory. This makes subsequent lookups fast, but can result in a fairly large memory overhead. If having a low memory overhead is important, you can use the `LowMemoryReader` by passing a `file_reader` argument to `MaxMindDB.new`. For example: ```ruby db = MaxMindDB.new('./GeoLite2-City.mmdb', MaxMindDB::LOW_MEMORY_FILE_READER) ret = db.lookup('74.125.225.224') ``` The `LowMemoryReader` will not load the entire database into memory. It's important to note that for Ruby versions lower than `2.5.0`, the `LowMemoryReader` is not process safe. Forking a process after initializing a `MaxMindDB` instance can lead to unexpected results. For Ruby versions >= `2.5.0`, `LowMemoryReader` uses `File.pread` which works safely in forking environments. ## Contributing 1. Fork it ( http://github.com/yhirose/maxminddb/fork ) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request ## Also see * [GeoLite2City](https://github.com/barsoom/geolite2_city), a Gem bundling the GeoLite2 City database. ruby-maxminddb-0.1.22/Rakefile000066400000000000000000000014761351162662300162000ustar00rootroot00000000000000require "bundler/gem_tasks" require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) desc "Downloads maxmind free DBs if required" task :ensure_maxmind_files do unless File.exist?('spec/cache/GeoLite2-City.mmdb') sh 'curl http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz -o spec/cache/GeoLite2-City.mmdb.gz' sh 'gunzip spec/cache/GeoLite2-City.mmdb.gz' end unless File.exist?('spec/cache/GeoLite2-Country.mmdb') sh 'curl http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz -o spec/cache/GeoLite2-Country.mmdb.gz' sh 'gunzip spec/cache/GeoLite2-Country.mmdb.gz' end end desc "Downloads maxmind free DBs if required and runs all specs" task ensure_maxmind_files_and_spec: [:ensure_maxmind_files, :spec] task default: :ensure_maxmind_files_and_spec ruby-maxminddb-0.1.22/lib/000077500000000000000000000000001351162662300152715ustar00rootroot00000000000000ruby-maxminddb-0.1.22/lib/maxminddb.rb000066400000000000000000000143021351162662300175610ustar00rootroot00000000000000require "maxminddb/version" require 'maxminddb/result' require 'maxminddb/reader' require 'ipaddr' module MaxMindDB # The default reader for MaxMindDB files. Reads the database into memory. # This creates a higher memory overhead, but faster lookup times. DEFAULT_FILE_READER = proc { |path| File.binread(path) } # A low memory file reader for MaxMindDB files. Avoids reading the database # into memory. Has a lower memory footprint but slower lookup times. LOW_MEMORY_FILE_READER = proc { |path| MaxMindDB::LowMemoryReader.new(path) } def self.new(path, file_reader=DEFAULT_FILE_READER) Client.new(path, file_reader) end class Client METADATA_BEGIN_MARKER = ([0xAB, 0xCD, 0xEF].pack('C*') + 'MaxMind.com').encode('ascii-8bit', 'ascii-8bit') DATA_SECTION_SEPARATOR_SIZE = 16 SIZE_BASE_VALUES = [0, 29, 285, 65821] POINTER_BASE_VALUES = [0, 0, 2048, 526336] attr_reader :metadata # An IP that is used instead of local IPs attr_accessor :local_ip_alias def initialize(path, file_reader = DEFAULT_FILE_READER) @path = path @data = file_reader.call(path) pos = @data.rindex(METADATA_BEGIN_MARKER) raise 'invalid file format' unless pos pos += METADATA_BEGIN_MARKER.size @metadata = decode(pos, 0)[1] @ip_version = @metadata['ip_version'] @node_count = @metadata['node_count'] @node_byte_size = @metadata['record_size'] * 2 / 8 @search_tree_size = @node_count * @node_byte_size end def inspect "#" end def lookup(ip_or_hostname) if @local_ip_alias && is_local?(ip_or_hostname) ip_or_hostname = @local_ip_alias end node_no = 0 addr = addr_from_ip(ip_or_hostname) start_idx = @ip_version == 4 ? 96 : 0 for i in start_idx ... 128 flag = (addr >> (127 - i)) & 1 next_node_no = read_record(node_no, flag) if next_node_no == 0 raise 'invalid file format' elsif next_node_no >= @node_count data_section_start = @search_tree_size + DATA_SECTION_SEPARATOR_SIZE pos = (next_node_no - @node_count) - DATA_SECTION_SEPARATOR_SIZE result = decode(pos, data_section_start)[1] result['network'] = network_from_addr(addr, i) unless result.empty? return MaxMindDB::Result.new(result) else node_no = next_node_no end end raise 'invalid file format' end private def read_record(node_no, flag) rec_byte_size = @node_byte_size / 2 pos = @node_byte_size * node_no middle = @data[pos + rec_byte_size].ord if @node_byte_size.odd? if flag == 0 # left val = read_value(pos, 0, rec_byte_size) val += ((middle & 0xf0) << 20) if middle else # right val = read_value(pos + @node_byte_size - rec_byte_size, 0, rec_byte_size) val += ((middle & 0xf) << 24) if middle end val end def decode(pos, base_pos) ctrl = @data[pos + base_pos].ord pos += 1 type = ctrl >> 5 if type == 1 # pointer size = ((ctrl >> 3) & 0x3) + 1 v1 = ctrl & 0x7 v2 = read_value(pos, base_pos, size) pos += size pointer = (v1 << (8 * size)) + v2 + POINTER_BASE_VALUES[size] val = decode(pointer, base_pos)[1] else if type == 0 # extended type type = 7 + @data[pos + base_pos].ord pos += 1 end size = ctrl & 0x1f if size >= 29 byte_size = size - 29 + 1 val = read_value(pos, base_pos, byte_size) pos += byte_size size = val + SIZE_BASE_VALUES[byte_size] end case type when 2 # utf8 val = @data[pos + base_pos, size].encode('utf-8', 'utf-8') pos += size when 3 # double val = @data[pos + base_pos, size].unpack('G')[0] pos += size when 4 # bytes val = @data[pos + base_pos, size] pos += size when 5 # unsigned 16-bit int val = read_value(pos, base_pos, size) pos += size when 6 # unsigned 32-bit int val = read_value(pos, base_pos, size) pos += size when 7 # map val = {} size.times do pos, k = decode(pos, base_pos) pos, v = decode(pos, base_pos) val[k] = v end when 8 # signed 32-bit int v1 = @data[pos + base_pos, size].unpack('N')[0] bits = size * 8 val = (v1 & ~(1 << bits)) - (v1 & (1 << bits)) pos += size when 9 # unsigned 64-bit int val = read_value(pos, base_pos, size) pos += size when 10 # unsigned 128-bit int val = read_value(pos, base_pos, size) pos += size when 11 # array val = [] size.times do pos, v = decode(pos, base_pos) val.push(v) end when 12 # data cache container raise 'TODO:' when 13 # end marker val = nil when 14 # boolean val = (size != 0) when 15 # float val = @data[pos + base_pos, size].unpack('g')[0] pos += size end end [pos, val] end def read_value(pos, base_pos, size) bytes = @data[pos + base_pos, size].unpack('C*') bytes.inject(0){|r, v| (r << 8) + v } end def addr_from_ip(ip_or_hostname) klass = ip_or_hostname.class return ip_or_hostname if RUBY_VERSION.to_f < 2.4 && (klass == Fixnum || klass == Bignum) return ip_or_hostname if RUBY_VERSION.to_f >= 2.4 && klass == Integer addr = IPAddr.new(ip_or_hostname) addr = addr.ipv4_compat if addr.ipv4? addr.to_i end def network_from_addr(addr, i) fam = addr > 4294967295 ? Socket::AF_INET6 : Socket::AF_INET ip = IPAddr.new(addr, family = fam) subnet_size = ip.ipv4? ? i - 96 + 1 : i + 1 subnet = IPAddr.new("#{ip}/#{subnet_size}") "#{subnet}/#{subnet_size}" end def is_local?(ip_or_hostname) ["127.0.0.1", "localhost", "::1", "0000::1", "0:0:0:0:0:0:0:1"].include? ip_or_hostname end end end # vim: et ts=2 sw=2 ff=unix ruby-maxminddb-0.1.22/lib/maxminddb/000077500000000000000000000000001351162662300172345ustar00rootroot00000000000000ruby-maxminddb-0.1.22/lib/maxminddb/reader.rb000066400000000000000000000014771351162662300210340ustar00rootroot00000000000000 require 'thread' module MaxMindDB class LowMemoryReader METADATA_MAX_SIZE = 128 * 1024 def initialize(path) @mutex = Mutex.new @file = File.open(path, 'rb') end def [](pos, length=1) atomic_read(length, pos) end def rindex(search) base = [0, @file.size - METADATA_MAX_SIZE].max tail = atomic_read(METADATA_MAX_SIZE, base) pos = tail.rindex(search) return nil if pos.nil? base + pos end def atomic_read(length, pos) # Prefer `pread` in environments where it is available. `pread` provides # atomic file access across processes. if @file.respond_to?(:pread) @file.pread(length, pos) else @mutex.synchronize do @file.seek(pos) @file.read(length) end end end end end ruby-maxminddb-0.1.22/lib/maxminddb/result.rb000066400000000000000000000025321351162662300211010ustar00rootroot00000000000000require_relative 'result/location' require_relative 'result/named_location' require_relative 'result/postal' require_relative 'result/subdivisions' require_relative 'result/traits' module MaxMindDB class Result def initialize(raw) @raw = raw || {} end def [](attr) raw[attr] end def city @_city ||= NamedLocation.new(raw['city']) end def continent @_continent ||= NamedLocation.new(raw['continent']) end def country @_country ||= NamedLocation.new(raw['country']) end def found? !raw.empty? end def location @_location ||= Location.new(raw['location']) end def postal @_postal ||= Postal.new(raw['postal']) end def registered_country @_registered_country ||= NamedLocation.new(raw['registered_country']) end def represented_country @_represented_country ||= NamedLocation.new(raw['represented_country']) end def subdivisions @_subdivisions ||= Subdivisions.new(raw['subdivisions']) end def traits @_traits ||= Traits.new(raw['traits']) end def connection_type @_connection_type ||= raw['connection_type'] end def network @_network ||= raw['network'] end def to_hash @_to_hash ||= raw.clone end private attr_reader :raw end end ruby-maxminddb-0.1.22/lib/maxminddb/result/000077500000000000000000000000001351162662300205525ustar00rootroot00000000000000ruby-maxminddb-0.1.22/lib/maxminddb/result/location.rb000066400000000000000000000007151351162662300227120ustar00rootroot00000000000000module MaxMindDB class Result class Location def initialize(raw) @raw = raw || {} end def latitude raw['latitude'] end def longitude raw['longitude'] end def metro_code raw['metro_code'] end def time_zone raw['time_zone'] end def accuracy_radius raw['accuracy_radius'] end private attr_reader :raw end end end ruby-maxminddb-0.1.22/lib/maxminddb/result/named_location.rb000066400000000000000000000007641351162662300240620ustar00rootroot00000000000000module MaxMindDB class Result class NamedLocation def initialize(raw) @raw = raw || {} end def code raw['code'] end def geoname_id raw['geoname_id'] end def is_in_european_union raw['is_in_european_union'] end def iso_code raw['iso_code'] end def name(locale = :en) raw['names'] && raw['names'][locale.to_s] end private attr_reader :raw end end end ruby-maxminddb-0.1.22/lib/maxminddb/result/postal.rb000066400000000000000000000003251351162662300224010ustar00rootroot00000000000000module MaxMindDB class Result class Postal def initialize(raw) @raw = raw || {} end def code raw['code'] end private attr_reader :raw end end end ruby-maxminddb-0.1.22/lib/maxminddb/result/subdivisions.rb000066400000000000000000000005241351162662300236210ustar00rootroot00000000000000module MaxMindDB class Result class Subdivisions < Array def initialize(raw) super((raw || []).map { |hash| NamedLocation.new(hash) }) end def most_specific last || NamedLocation.new({}) end def inspect "#" end end end end ruby-maxminddb-0.1.22/lib/maxminddb/result/traits.rb000066400000000000000000000005011351162662300224010ustar00rootroot00000000000000module MaxMindDB class Result class Traits def initialize(raw) @raw = raw || {} end def is_anonymous_proxy raw['is_anonymous_proxy'] end def is_satellite_provider raw['is_satellite_provider'] end private attr_reader :raw end end end ruby-maxminddb-0.1.22/lib/maxminddb/version.rb000066400000000000000000000000521351162662300212430ustar00rootroot00000000000000module MaxMindDB VERSION = "0.1.22" end ruby-maxminddb-0.1.22/maxminddb.gemspec000066400000000000000000000017301351162662300200340ustar00rootroot00000000000000# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'maxminddb/version' Gem::Specification.new do |spec| spec.name = "maxminddb" spec.version = MaxMindDB::VERSION spec.authors = ["yhirose"] spec.email = ["yuji.hirose.bug@gmail.com"] spec.summary = %q{MaxMind DB binary file reader.} spec.description = %q{Pure Ruby MaxMind DB (GeoIP2) binary file reader.} spec.homepage = "https://github.com/yhirose/maxminddb" spec.license = "MIT" spec.files = `git ls-files -z`.split("\x0") spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] spec.add_development_dependency "bundler", "~> 1.5" spec.add_development_dependency "rake" spec.add_development_dependency "rspec" spec.add_development_dependency "rspec-its" end ruby-maxminddb-0.1.22/spec/000077500000000000000000000000001351162662300154555ustar00rootroot00000000000000ruby-maxminddb-0.1.22/spec/cache/000077500000000000000000000000001351162662300165205ustar00rootroot00000000000000ruby-maxminddb-0.1.22/spec/cache/.gitkeep000066400000000000000000000000001351162662300201370ustar00rootroot00000000000000ruby-maxminddb-0.1.22/spec/data/000077500000000000000000000000001351162662300163665ustar00rootroot00000000000000ruby-maxminddb-0.1.22/spec/data/32bit_record_data.mmdb000066400000000000000000000024601351162662300225030ustar00rootroot00000000000000     *3*gg-DcityBidEnamesBen@Ezh_CN@IcontinentDcodeBAS BenDAsia F亚洲GcountryHiso_codeBCN BenEChina F中国Fcounty CispBid' F电信HlocationHlatitudeh@7hrxIlongitudeh@\YDCorg@Itime_zoneMAsia/ShanghaiLsubdivisions MB44 BenIGuangdong I广东省 Bid BenETokyo F东京  ' D MBJP BenEJapan F日本 n CispBid @ h@A׮zH h@ax xFCorgM东京I2TsInc JAsia/Tokyo MB13 Ben! @    (BOC BenGOceania I大洋洲 D MBAU BenIAustralia L澳大利亚 n Cisp!O h; h@`CorgU墨尔本BigRed集团 @ M@     ' D L n Cisp { h@: ԍxw h@] N4~Corg@ MB35 BenFFujian I福建省   ! D! n CispBid GAnycast h; h@`Corg]亚太互联网络信息中心 @ "5 Bid BenIHiroshima @  ' D!, n Cisp!O h@A2Y h@`g Corg]広島県中区大手町Energia通信公司 ! MB34 # MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochVf:Mdatabase_typeEGeoIPKdescriptionBenNGeoIP databaseJip_versionIlanguagesBenJnode_countKrecord_size ruby-maxminddb-0.1.22/spec/maxminddb/000077500000000000000000000000001351162662300174205ustar00rootroot00000000000000ruby-maxminddb-0.1.22/spec/maxminddb/result/000077500000000000000000000000001351162662300207365ustar00rootroot00000000000000ruby-maxminddb-0.1.22/spec/maxminddb/result/location_spec.rb000066400000000000000000000015651351162662300241140ustar00rootroot00000000000000require 'maxminddb' require 'rspec/its' describe MaxMindDB::Result::Location do subject(:result) { described_class.new(raw_result) } context "with a result" do let(:raw_result) { { "latitude"=>37.419200000000004, "longitude"=>-122.0574, "metro_code"=>"807", "time_zone"=>"America/Los_Angeles", "accuracy_radius"=>1000 } } its(:latitude) { should eq(37.419200000000004) } its(:longitude) { should eq(-122.0574) } its(:metro_code) { should eq("807") } its(:time_zone) { should eq("America/Los_Angeles") } its(:accuracy_radius) { should eq(1000) } end context "without a result" do let(:raw_result) { nil } its(:latitude) { should be_nil } its(:longitude) { should be_nil } its(:metro_code) { should be_nil } its(:time_zone) { should be_nil } its(:accuracy_radius) { should be_nil } end end ruby-maxminddb-0.1.22/spec/maxminddb/result/named_location_spec.rb000066400000000000000000000020101351162662300252420ustar00rootroot00000000000000# -*- encoding: utf-8 -*- require 'maxminddb' describe MaxMindDB::Result::NamedLocation do subject(:result) { described_class.new(raw_result) } context "with a result" do let(:raw_result) { { "geoname_id"=>6252001, "iso_code"=>"US", "names"=>{"de"=>"USA", "en"=>"United States", "es"=>"Estados Unidos", "fr"=>"États-Unis", "ja"=>"アメリカ合衆国", "pt-BR"=>"Estados Unidos", "ru"=>"США", "zh-CN"=>"美国"} } } its(:geoname_id) { should eq(6252001) } its(:iso_code) { should eq('US') } describe "name" do it 'should eq "United States"' do expect(result.name).to eq('United States') end context "with locale :ja" do it 'should eq "アメリカ合衆国"' do expect(result.name(:ja)).to eq('アメリカ合衆国') end end end end context "without a result" do let(:raw_result) { nil } its(:geoname_id) { should be_nil } its(:iso_code) { should be_nil } its(:name) { should be_nil } end end ruby-maxminddb-0.1.22/spec/maxminddb/result/postal_spec.rb000066400000000000000000000005361351162662300236030ustar00rootroot00000000000000require 'maxminddb' describe MaxMindDB::Result::Postal do subject(:result) { described_class.new(raw_result) } context "with a result" do let(:raw_result) { { "code"=>"94043" } } its(:code) { should eq("94043") } end context "without a result" do let(:raw_result) { nil } its(:code) { should be_nil } end end ruby-maxminddb-0.1.22/spec/maxminddb/result/subdivisions_spec.rb000066400000000000000000000036521351162662300250240ustar00rootroot00000000000000# -*- encoding: utf-8 -*- require 'maxminddb' describe MaxMindDB::Result::Subdivisions do subject(:subdivisions) { described_class.new(raw_subdivisions) } context "with multiple subdivisions" do let(:raw_subdivisions) { [{ "geoname_id"=>5037779, "iso_code"=>"MN", "names"=>{"en"=>"Minnesota"} }, { "geoname_id"=>123, "iso_code"=>"HP", "names"=>{"en"=>"Hennepin"} }] } it 'should be a kind of Array' do expect(subdivisions).to be_kind_of(Array) end it 'should return as many items as there are subdivisions passed in' do expect(subdivisions.length).to eq(raw_subdivisions.length) end it 'should contain only MaxMindDB::Result::NamedLocation' do expect(subdivisions.all? { |r| r.kind_of?(MaxMindDB::Result::NamedLocation)}).to be_truthy end describe "most_specific" do it 'should be a kind of MaxMindDB::Result::NamedLocation' do expect(subdivisions.most_specific).to be_kind_of(MaxMindDB::Result::NamedLocation) end it 'should eq "Hennepin" subdivision' do expect(subdivisions.most_specific.name).to eq("Hennepin") end end end context "without a result" do let(:raw_subdivisions) { nil } it 'should be a kind of Array' do expect(subdivisions).to be_kind_of(Array) end it 'should be empty' do expect(subdivisions.length).to eq(0) end describe "most_specific" do it 'should be a kind of MaxMindDB::Result::NamedLocation' do expect(subdivisions.most_specific).to be_kind_of(MaxMindDB::Result::NamedLocation) end it 'should be an empty MaxMindDB::Result::NamedLocation' do expect(subdivisions.most_specific.code).to eq(nil) expect(subdivisions.most_specific.geoname_id).to eq(nil) expect(subdivisions.most_specific.iso_code).to eq(nil) expect(subdivisions.most_specific.name).to eq(nil) end end end end ruby-maxminddb-0.1.22/spec/maxminddb/result/trait_spec.rb000066400000000000000000000017371351162662300234300ustar00rootroot00000000000000require 'maxminddb' describe MaxMindDB::Result::Traits do subject(:result) { described_class.new(raw_result) } context "with an is_anonymous_proxy result" do let(:raw_result) { { "is_anonymous_proxy"=>true } } its(:is_anonymous_proxy) { should eq(true) } its(:is_satellite_provider) { should eq(nil) } end context "with an is_satellite_provider result" do let(:raw_result) { { "is_satellite_provider"=>true } } its(:is_anonymous_proxy) { should eq(nil) } its(:is_satellite_provider) { should eq(true) } end context "with an all traits result" do let(:raw_result) { { "is_anonymous_proxy"=>true, "is_satellite_provider"=>true } } its(:is_anonymous_proxy) { should eq(true) } its(:is_satellite_provider) { should eq(true) } end context "without a result" do let(:raw_result) { nil } its(:is_anonymous_proxy) { should eq(nil) } its(:is_satellite_provider) { should eq(nil) } end end ruby-maxminddb-0.1.22/spec/maxminddb/result_spec.rb000066400000000000000000000215031351162662300222760ustar00rootroot00000000000000# -*- encoding: utf-8 -*- require 'maxminddb' describe MaxMindDB::Result do subject(:result) { described_class.new(raw_result) } let(:raw_result) { { "city"=>{ "geoname_id"=>5375480, "names"=>{"de"=>"Mountain View", "en"=>"Mountain View", "fr"=>"Mountain View", "ru"=>"Маунтин-Вью", "zh-CN"=>"芒廷维尤"} }, "continent"=>{ "code"=>"NA", "geoname_id"=>6255149, "names"=>{"de"=>"Nordamerika", "en"=>"North America", "es"=>"Norteamérica", "fr"=>"Amérique du Nord", "ja"=>"北アメリカ", "pt-BR"=>"América do Norte", "ru"=>"Северная Америка", "zh-CN"=>"北美洲"} }, "country"=>{ "geoname_id"=>6252001, "iso_code"=>"US", "names"=>{"de"=>"USA", "en"=>"United States", "es"=>"Estados Unidos", "fr"=>"États-Unis", "ja"=>"アメリカ合衆国", "pt-BR"=>"Estados Unidos", "ru"=>"США", "zh-CN"=>"美国"} }, "location"=>{ "latitude"=>37.419200000000004, "longitude"=>-122.0574, "metro_code"=>"807", "time_zone"=>"America/Los_Angeles" }, "postal"=>{ "code"=>"94043" }, "registered_country"=>{ "geoname_id"=>6252001, "iso_code"=>"US", "names"=>{"de"=>"USA", "en"=>"United States", "es"=>"Estados Unidos", "fr"=>"États-Unis", "ja"=>"アメリカ合衆国", "pt-BR"=>"Estados Unidos", "ru"=>"США", "zh-CN"=>"美国"} }, "represented_country"=>{ "geoname_id"=>6252001, "iso_code"=>"US", "names"=>{"de"=>"USA", "en"=>"United States", "es"=>"Estados Unidos", "fr"=>"États-Unis", "ja"=>"アメリカ合衆国", "pt-BR"=>"Estados Unidos", "ru"=>"США", "zh-CN"=>"美国"} }, "traits"=>{ "is_satellite_provider"=>true }, "subdivisions"=>[ { "geoname_id"=>5332921, "iso_code"=>"CA", "names"=>{"de"=>"Kalifornien", "en"=>"California", "es"=>"California", "fr"=>"Californie", "ja"=>"カリフォルニア州", "pt-BR"=>"Califórnia", "ru"=>"Калифорния", "zh-CN"=>"加利福尼亚州"} } ], "connection_type"=>"Dialup" } } describe '#[]' do it 'should return the given key on the raw result' do expect(result['city']).to eq(raw_result['city']) end end describe '#to_hash' do it 'should be a kind of Hash' do expect(result.to_hash).to be_kind_of(Hash) end it 'should return full raw data' do expect(result.to_hash).to eq(raw_result) end end describe '#city' do context 'with a result' do it 'should be a kind of MaxMindDB::Result::NamedLocation' do expect(result.city).to be_kind_of(MaxMindDB::Result::NamedLocation) end it 'should initialize the location with the city attributes' do expect(MaxMindDB::Result::NamedLocation).to receive(:new).with(raw_result['city']) result.city end end context "without a result" do let(:raw_result) { nil } it 'should be a kind of MaxMindDB::Result::NamedLocation' do expect(result.city).to be_kind_of(MaxMindDB::Result::NamedLocation) end end end describe '#continent' do context 'with a result' do it 'should be a kind of MaxMindDB::Result::NamedLocation' do expect(result.continent).to be_kind_of(MaxMindDB::Result::NamedLocation) end it 'should initialize the location with the continent attributes' do expect(MaxMindDB::Result::NamedLocation).to receive(:new).with(raw_result['continent']) result.continent end end context "without a result" do let(:raw_result) { nil } it 'should be a kind of MaxMindDB::Result::NamedLocation' do expect(result.continent).to be_kind_of(MaxMindDB::Result::NamedLocation) end end end describe '#country' do context 'with a result' do it 'should be a kind of MaxMindDB::Result::NamedLocation' do expect(result.country).to be_kind_of(MaxMindDB::Result::NamedLocation) end it 'should initialize the location with the country attributes' do expect(MaxMindDB::Result::NamedLocation).to receive(:new).with(raw_result['country']) result.country end end context "without a result" do let(:raw_result) { nil } it 'should be a kind of MaxMindDB::Result::NamedLocation' do expect(result.country).to be_kind_of(MaxMindDB::Result::NamedLocation) end end end describe '#found?' do context 'with a result' do it 'should return true' do expect(result.found?).to be_truthy end end context 'without a result' do let(:raw_result) { nil } it 'should return false' do expect(result.found?).to be_falsy end end end describe '#location' do context 'with a result' do it 'should return a kind of MaxMindDB::Result::Location' do expect(result.location).to be_kind_of(MaxMindDB::Result::Location) end it 'should initialize the object with the location attributes' do expect(MaxMindDB::Result::Location).to receive(:new).with(raw_result['location']) result.location end end context "without a result" do let(:raw_result) { nil } it 'should be a kind of MaxMindDB::Result::Location' do expect(result.location).to be_kind_of(MaxMindDB::Result::Location) end end end describe '#postal' do context 'with a result' do it 'should return a kind of MaxMindDB::Result::Postal' do expect(result.postal).to be_kind_of(MaxMindDB::Result::Postal) end it 'should initialize the object with the postal attributes' do expect(MaxMindDB::Result::Postal).to receive(:new).with(raw_result['postal']) result.postal end end context "without a result" do let(:raw_result) { nil } it 'should be a kind of MaxMindDB::Result::Postal' do expect(result.postal).to be_kind_of(MaxMindDB::Result::Postal) end end end describe '#registered_country' do context 'with a result' do it 'should be a kind of MaxMindDB::Result::NamedLocation' do expect(result.registered_country).to be_kind_of(MaxMindDB::Result::NamedLocation) end it 'should initialize the location with the registered_country attributes' do expect(MaxMindDB::Result::NamedLocation).to receive(:new).with(raw_result['registered_country']) result.registered_country end end end describe '#represented_country' do context 'with a result' do it 'should be a kind of MaxMindDB::Result::NamedLocation' do expect(result.represented_country).to be_kind_of(MaxMindDB::Result::NamedLocation) end it 'should initialize the location with the represented_country attributes' do expect(MaxMindDB::Result::NamedLocation).to receive(:new).with(raw_result['represented_country']) result.represented_country end end end describe '#subdivisions' do context 'with a result' do it 'should be a kind of Array' do expect(result.subdivisions).to be_kind_of(Array) end it 'should return as many results as there are subdivisions passed in' do expect(result.subdivisions.length).to eq(raw_result['subdivisions'].length) end it 'should contain only MaxMindDB::Result::NamedLocation' do expect(result.subdivisions.all? { |r| r.kind_of?(MaxMindDB::Result::NamedLocation)}).to be_truthy end it 'should initialize the location with the correct attributes' do expect(MaxMindDB::Result::NamedLocation).to receive(:new).with(raw_result['subdivisions'].first) result.subdivisions end end context 'without a result' do let(:raw_result) { nil } it 'should be a kind of Array' do expect(result.subdivisions).to be_kind_of(Array) end it 'should be empty' do expect(result.subdivisions).to be_empty end end end describe '#traits' do context 'with a result' do it 'should return a kind of MaxMindDB::Result::Traits' do expect(result.traits).to be_kind_of(MaxMindDB::Result::Traits) end it 'should initialize the object with the traits attributes' do expect(MaxMindDB::Result::Traits).to receive(:new).with(raw_result['traits']) result.traits end end context "without a result" do let(:raw_result) { nil } it 'should be a kind of MaxMindDB::Result::Traits' do expect(result.traits).to be_kind_of(MaxMindDB::Result::Traits) end end end describe '#connection_type' do context 'with a result' do it 'should return a String representation of connection type' do expect(result.connection_type).to eq("Dialup") end end context "without a result" do let(:raw_result) { nil } it 'should be nil' do expect(result.connection_type).to be_nil end end end end ruby-maxminddb-0.1.22/spec/maxminddb_spec.rb000066400000000000000000000160151351162662300207620ustar00rootroot00000000000000require 'maxminddb' describe MaxMindDB do [ ['default file reader', MaxMindDB::DEFAULT_FILE_READER], ['low memory file reader', MaxMindDB::LOW_MEMORY_FILE_READER], ].each do |file_reader| description, reader = file_reader describe description do let(:city_db) { MaxMindDB.new('spec/cache/GeoLite2-City.mmdb', reader) } let(:country_db) { MaxMindDB.new('spec/cache/GeoLite2-Country.mmdb', reader) } let(:rec32_db) { MaxMindDB.new('spec/data/32bit_record_data.mmdb', reader) } context 'for the ip 74.125.225.224' do let(:ip) { '74.125.225.224' } it 'returns a MaxMindDB::Result' do expect(city_db.lookup(ip)).to be_kind_of(MaxMindDB::Result) end it 'finds data' do expect(city_db.lookup(ip)).to be_found end it 'returns Mountain View as the English name' do expect(city_db.lookup(ip).city.name).to eq('Alameda') end it 'returns -122.0574 as the longitude' do expect(city_db.lookup(ip).location.longitude).to eq(-122.2788) end it 'returns nil for is_anonymous_proxy' do expect(city_db.lookup(ip).traits.is_anonymous_proxy).to eq(nil) end it 'returns United States as the English country name' do expect(country_db.lookup(ip).country.name).to eq('United States') end it 'returns false for the is_in_european_union' do expect(country_db.lookup(ip).country.is_in_european_union).to eq(nil) end it 'returns US as the country iso code' do expect(country_db.lookup(ip).country.iso_code).to eq('US') end it 'returns 74.125.192.0/18 as network' do expect(country_db.lookup(ip).network).to eq('74.125.192.0/18') end context 'as a Integer' do let(:integer_ip) { IPAddr.new(ip).to_i } it 'returns a MaxMindDB::Result' do expect(city_db.lookup(integer_ip)).to be_kind_of(MaxMindDB::Result) end it 'returns Mountain View as the English name' do expect(city_db.lookup(integer_ip).city.name).to eq('Alameda') end it 'returns United States as the English country name' do expect(country_db.lookup(integer_ip).country.name).to eq('United States') end end end context 'for the ip 2001:708:510:8:9a6:442c:f8e0:7133' do let(:ip) { '2001:708:510:8:9a6:442c:f8e0:7133' } it 'finds data' do expect(city_db.lookup(ip)).to be_found end it 'returns true for the is_in_european_union' do expect(country_db.lookup(ip).country.is_in_european_union).to eq(true) end it 'returns FI as the country iso code' do expect(country_db.lookup(ip).country.iso_code).to eq('FI') end it 'returns 2001:708::/32 as network' do expect(country_db.lookup(ip).network).to eq('2001:708::/32') end context 'as an integer' do let(:integer_ip) { IPAddr.new(ip).to_i } it 'returns FI as the country iso code' do expect(country_db.lookup(integer_ip).country.iso_code).to eq('FI') end end end context 'for a Canadian ipv6' do let(:ip) { '2607:5300:60:72ba::' } it 'finds data' do expect(city_db.lookup(ip)).to be_found end it 'returns true for the is_in_european_union' do expect(country_db.lookup(ip).country.is_in_european_union).to be_falsey end it 'returns CA as the country iso code' do expect(country_db.lookup(ip).country.iso_code).to eq('CA') end end context 'for a German IPv6' do let(:ip) { '2a01:488:66:1000:2ea3:495e::1' } it 'finds data' do expect(city_db.lookup(ip)).to be_found end it 'returns true for the is_in_european_union' do expect(country_db.lookup(ip).country.is_in_european_union).to eq(true) end it 'returns DE as the country iso code' do expect(country_db.lookup(ip).country.iso_code).to eq('DE') end end context 'for the ip 127.0.0.1' do let(:ip) { '127.0.0.1' } it 'returns a MaxMindDB::Result' do expect(city_db.lookup(ip)).to be_kind_of(MaxMindDB::Result) end it "doesn't find data" do expect(city_db.lookup(ip)).to_not be_found end end context 'for local ip addresses' do let(:ip) { '127.0.0.1' } context 'for city_db' do before do city_db.local_ip_alias = '74.125.225.224' end it 'returns a MaxMindDB::Result' do expect(city_db.lookup(ip)).to be_kind_of(MaxMindDB::Result) end it 'finds data' do expect(city_db.lookup(ip)).to be_found end it 'returns Mountain View as the English name' do expect(city_db.lookup(ip).city.name).to eq('Alameda') end it 'returns -122.0574 as the longitude' do expect(city_db.lookup(ip).location.longitude).to eq(-122.2788) end it 'returns nil for is_anonymous_proxy' do expect(city_db.lookup(ip).traits.is_anonymous_proxy).to eq(nil) end end context 'for country_db' do before do country_db.local_ip_alias = '74.125.225.224' end it 'returns United States as the English country name' do expect(country_db.lookup(ip).country.name).to eq('United States') end it 'returns false for the is_in_european_union' do expect(country_db.lookup(ip).country.is_in_european_union).to eq(nil) end it 'returns US as the country iso code' do expect(country_db.lookup(ip).country.iso_code).to eq('US') end end end context 'for 32bit record data' do let(:ip) { '1.0.16.1' } it 'finds data' do expect(rec32_db.lookup(ip)).to be_found end end context 'test ips' do [ ['185.23.124.1', 'SA'], ['178.72.254.1', 'CZ'], ['95.153.177.210', 'RU'], ['200.148.105.119', 'BR'], ['195.59.71.43', 'GB'], ['179.175.47.87', 'BR'], ['202.67.40.50', 'ID'], ].each do |ip, iso| it 'returns a MaxMindDB::Result' do expect(city_db.lookup(ip)).to be_kind_of(MaxMindDB::Result) end it "returns #{iso} as the country iso code" do expect(country_db.lookup(ip).country.iso_code).to eq(iso) end end end context 'test boolean data' do let(:ip) { '41.194.0.1' } it 'returns true for the is_satellite_provider trait' do expect(city_db.lookup(ip).traits.is_satellite_provider).to eq(nil) end # There are no false booleans in the database that we can test. # False values are simply omitted. end end end end # vim: et ts=2 sw=2 ff=unix