ipregistry 1.0.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.
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ipregistry
4
+ # Value objects wrapping the JSON payloads returned by the Ipregistry API.
5
+ #
6
+ # Nested objects are always present (never nil), so chained access such as
7
+ # +info.location.country.name+ never raises even when the API omitted a
8
+ # section; absent fields return nil and absent flags return false.
9
+ module Models
10
+ # Base class for all response models. Wraps the decoded JSON hash and
11
+ # exposes convenient readers declared with a small class-level DSL.
12
+ class Base
13
+ # @param data [Hash, nil] the decoded JSON payload
14
+ def initialize(data = {})
15
+ @data = data.is_a?(Hash) ? data : {}
16
+ end
17
+
18
+ # The raw decoded payload backing this model.
19
+ # @return [Hash]
20
+ def to_h
21
+ @data
22
+ end
23
+
24
+ # Raw access to any field of the payload, including ones without a
25
+ # dedicated reader.
26
+ def [](key)
27
+ @data[key.to_s]
28
+ end
29
+
30
+ def ==(other)
31
+ other.instance_of?(self.class) && other.to_h == @data
32
+ end
33
+ alias eql? ==
34
+
35
+ def hash
36
+ [self.class, @data].hash
37
+ end
38
+
39
+ def inspect
40
+ "#<#{self.class.name} #{@data.inspect}>"
41
+ end
42
+
43
+ class << self
44
+ private
45
+
46
+ # Declares readers returning the raw value of same-named JSON fields.
47
+ def field(*names)
48
+ names.each do |name|
49
+ key = name.to_s
50
+ define_method(name) { @data[key] }
51
+ end
52
+ end
53
+
54
+ # Declares a predicate method (+name?+) for a boolean JSON field.
55
+ def flag(name, key: name.to_s)
56
+ define_method(:"#{name}?") { @data[key] ? true : false }
57
+ end
58
+
59
+ # Declares a reader wrapping a nested JSON object in another model.
60
+ # The wrapped object is always returned, even when the field is
61
+ # absent, so chained access is nil-safe.
62
+ def embeds(name, model, key: name.to_s)
63
+ define_method(name) do
64
+ @embedded ||= {}
65
+ @embedded[name] ||= Models.const_get(model).new(@data[key])
66
+ end
67
+ end
68
+
69
+ # Declares a reader wrapping a nested JSON array in a list of models.
70
+ def embeds_many(name, model, key: name.to_s)
71
+ define_method(name) do
72
+ @embedded ||= {}
73
+ @embedded[name] ||= begin
74
+ klass = Models.const_get(model)
75
+ elements = @data[key]
76
+ elements.is_a?(Array) ? elements.map { |element| klass.new(element) }.freeze : [].freeze
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ipregistry
4
+ module Models
5
+ # Mobile carrier information associated with an IP address. MCC is the
6
+ # Mobile Country Code and MNC the Mobile Network Code.
7
+ class Carrier < Base
8
+ field :name, :mcc, :mnc
9
+ end
10
+
11
+ # Ownership information for the IP address. The type classifies the kind
12
+ # of company ("business", "education", "government", "hosting", or "isp").
13
+ class Company < Base
14
+ field :name, :domain, :type
15
+ end
16
+
17
+ # Network connection information for the IP address. The ASN is the
18
+ # Autonomous System Number (nil when unknown), and the type classifies
19
+ # the network ("business", "education", "government", "hosting",
20
+ # "inactive", or "isp").
21
+ class Connection < Base
22
+ field :asn, :domain, :organization, :route, :type
23
+ end
24
+
25
+ # Prefix and suffix applied around a formatted monetary value (for example
26
+ # the currency symbol and a sign).
27
+ class CurrencyFormatAffix < Base
28
+ field :prefix, :suffix
29
+ end
30
+
31
+ # How monetary values are formatted for a currency.
32
+ class CurrencyFormat < Base
33
+ field :decimal_separator, :group_separator
34
+
35
+ embeds :negative, :CurrencyFormatAffix
36
+ embeds :positive, :CurrencyFormatAffix
37
+ end
38
+
39
+ # Currency information for the IP address location.
40
+ class Currency < Base
41
+ field :code, :name, :name_native, :plural, :plural_native,
42
+ :symbol, :symbol_native
43
+
44
+ embeds :format, :CurrencyFormat
45
+ end
46
+
47
+ # Threat-intelligence flags for the IP address.
48
+ class Security < Base
49
+ flag :abuser, key: "is_abuser"
50
+ flag :attacker, key: "is_attacker"
51
+ flag :bogon, key: "is_bogon"
52
+ flag :cloud_provider, key: "is_cloud_provider"
53
+ flag :proxy, key: "is_proxy"
54
+ flag :relay, key: "is_relay"
55
+ flag :tor, key: "is_tor"
56
+ flag :tor_exit, key: "is_tor_exit"
57
+ flag :anonymous, key: "is_anonymous"
58
+ flag :threat, key: "is_threat"
59
+ flag :vpn, key: "is_vpn"
60
+ end
61
+
62
+ # Time zone information for the IP address location. The offset is the
63
+ # current offset from UTC in seconds.
64
+ class TimeZone < Base
65
+ field :id, :abbreviation, :current_time, :name, :offset
66
+
67
+ flag :in_daylight_saving
68
+ end
69
+
70
+ # The comprehensive set of information associated with an IP address
71
+ # returned by the Ipregistry API.
72
+ #
73
+ # Nested objects (carrier, company, connection, currency, location,
74
+ # security, and time_zone) are always present, so chained access never
75
+ # raises even when the API omitted them; absent fields return nil.
76
+ class IpInfo < Base
77
+ # ip is the IP address the data refers to; type is the IP version
78
+ # ("IPv4" or "IPv6"); hostname is the reverse-DNS hostname, when
79
+ # hostname resolution is requested and available.
80
+ field :ip, :type, :hostname
81
+
82
+ embeds :carrier, :Carrier
83
+ embeds :company, :Company
84
+ embeds :connection, :Connection
85
+ embeds :currency, :Currency
86
+ embeds :location, :Location
87
+ embeds :security, :Security
88
+ embeds :time_zone, :TimeZone
89
+
90
+ def ipv4? = @data["type"] == "IPv4"
91
+
92
+ def ipv6? = @data["type"] == "IPv6"
93
+ end
94
+
95
+ # IpInfo enriched with parsed User-Agent data. Returned by
96
+ # {Client#lookup_origin}, where the User-Agent of the calling client is
97
+ # known.
98
+ class RequesterIpInfo < IpInfo
99
+ # The parsed User-Agent of the requester, or nil when the API did not
100
+ # return any.
101
+ # @return [UserAgent, nil]
102
+ def user_agent
103
+ value = @data["user_agent"]
104
+ return nil unless value.is_a?(Hash)
105
+
106
+ @embedded ||= {}
107
+ @embedded[:user_agent] ||= UserAgent.new(value)
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ipregistry
4
+ module Models
5
+ # Continent-level information for a location.
6
+ class Continent < Base
7
+ field :code, :name
8
+ end
9
+
10
+ # Language information.
11
+ class Language < Base
12
+ field :code, :name
13
+
14
+ # The language's name in the language itself.
15
+ def native_name
16
+ @data["native"]
17
+ end
18
+ end
19
+
20
+ # Representations of a country flag across several icon sets.
21
+ class Flag < Base
22
+ field :emoji, :emoji_unicode, :emojitwo, :noto, :twemoji, :wikimedia
23
+ end
24
+
25
+ # Country-level information for a location.
26
+ class Country < Base
27
+ # area is the total land area in square kilometers; borders lists the
28
+ # ISO 3166-1 alpha-2 codes of bordering countries; code is the ISO
29
+ # 3166-1 alpha-2 country code (for example "US"); population is the
30
+ # estimated number of inhabitants; population_density is the number of
31
+ # inhabitants per square kilometer; tld is the country-code top-level
32
+ # domain (for example ".us").
33
+ field :area, :calling_code, :capital, :code, :name,
34
+ :population, :population_density, :tld
35
+
36
+ embeds :flag, :Flag
37
+ embeds_many :languages, :Language
38
+
39
+ # ISO 3166-1 alpha-2 codes of bordering countries.
40
+ # @return [Array<String>]
41
+ def borders
42
+ value = @data["borders"]
43
+ value.is_a?(Array) ? value : []
44
+ end
45
+ end
46
+
47
+ # Administrative region (state/province) information. The code is
48
+ # typically the ISO 3166-2 subdivision code.
49
+ class Region < Base
50
+ field :code, :name
51
+ end
52
+
53
+ # Geographical location associated with an IP address.
54
+ class Location < Base
55
+ # city, postal, and the decimal-degree latitude/longitude (nil when
56
+ # unavailable).
57
+ field :city, :postal, :latitude, :longitude
58
+
59
+ embeds :continent, :Continent
60
+ embeds :country, :Country
61
+ embeds :region, :Region
62
+ # The primary language spoken at the location.
63
+ embeds :language, :Language
64
+
65
+ # Whether the location is within a European Union member state.
66
+ flag :in_eu
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ipregistry
4
+ module Models
5
+ # Device data parsed from a User-Agent string.
6
+ class UserAgentDevice < Base
7
+ field :brand, :name, :type
8
+ end
9
+
10
+ # Layout-engine data parsed from a User-Agent string.
11
+ class UserAgentEngine < Base
12
+ field :name, :type, :version, :version_major
13
+ end
14
+
15
+ # Operating-system data parsed from a User-Agent string.
16
+ class UserAgentOperatingSystem < Base
17
+ field :name, :type, :version
18
+ end
19
+
20
+ # Structured data parsed from a raw User-Agent string. The header field
21
+ # is the raw User-Agent string that was parsed.
22
+ class UserAgent < Base
23
+ field :header, :name, :type, :version, :version_major
24
+
25
+ embeds :device, :UserAgentDevice
26
+ embeds :engine, :UserAgentEngine
27
+ embeds :operating_system, :UserAgentOperatingSystem, key: "os"
28
+ alias os operating_system
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ipregistry
4
+ # Version of the client library, reported as part of the User-Agent header
5
+ # sent with every request to the Ipregistry API.
6
+ VERSION = "1.0.0"
7
+ end
data/lib/ipregistry.rb ADDED
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "ipregistry/version"
4
+ require_relative "ipregistry/errors"
5
+ require_relative "ipregistry/cache"
6
+ require_relative "ipregistry/models/base"
7
+ require_relative "ipregistry/models/location"
8
+ require_relative "ipregistry/models/ip_info"
9
+ require_relative "ipregistry/models/user_agent"
10
+ require_relative "ipregistry/batch_response"
11
+ require_relative "ipregistry/client"
12
+
13
+ # Official Ruby client for the Ipregistry API (https://ipregistry.co), a fast
14
+ # and reliable IP geolocation and threat data service.
15
+ #
16
+ # client = Ipregistry::Client.new("YOUR_API_KEY")
17
+ # info = client.lookup("8.8.8.8")
18
+ # info.location.country.name # => "United States"
19
+ # info.security.vpn? # => false
20
+ module Ipregistry
21
+ # Reports whether the given raw User-Agent string looks like a crawler or
22
+ # bot. It is a lightweight heuristic — useful for skipping IP lookups on
23
+ # automated traffic — that matches the substrings "bot", "spider", and
24
+ # "slurp" case-insensitively.
25
+ #
26
+ # unless Ipregistry.bot?(request.user_agent)
27
+ # info = client.lookup(request.remote_ip)
28
+ # end
29
+ def self.bot?(user_agent)
30
+ value = user_agent.to_s.downcase
31
+ value.include?("bot") || value.include?("spider") || value.include?("slurp")
32
+ end
33
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ipregistry
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Ipregistry
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: Look up IP addresses (single, batch, or the requester's own) and parse
13
+ User-Agent strings with the Ipregistry API. Returns carrier, company, connection,
14
+ currency, location, time zone, and threat data. Zero runtime dependencies, optional
15
+ in-memory caching, and automatic retries with exponential backoff.
16
+ email:
17
+ - support@ipregistry.co
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - CHANGELOG.md
23
+ - LICENSE
24
+ - README.md
25
+ - lib/ipregistry.rb
26
+ - lib/ipregistry/batch_response.rb
27
+ - lib/ipregistry/cache.rb
28
+ - lib/ipregistry/client.rb
29
+ - lib/ipregistry/errors.rb
30
+ - lib/ipregistry/models/base.rb
31
+ - lib/ipregistry/models/ip_info.rb
32
+ - lib/ipregistry/models/location.rb
33
+ - lib/ipregistry/models/user_agent.rb
34
+ - lib/ipregistry/version.rb
35
+ homepage: https://github.com/ipregistry/ipregistry-ruby
36
+ licenses:
37
+ - Apache-2.0
38
+ metadata:
39
+ homepage_uri: https://github.com/ipregistry/ipregistry-ruby
40
+ source_code_uri: https://github.com/ipregistry/ipregistry-ruby
41
+ changelog_uri: https://github.com/ipregistry/ipregistry-ruby/blob/main/CHANGELOG.md
42
+ bug_tracker_uri: https://github.com/ipregistry/ipregistry-ruby/issues
43
+ documentation_uri: https://ipregistry.co/docs
44
+ rubygems_mfa_required: 'true'
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '3.1'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.6.9
60
+ specification_version: 4
61
+ summary: Official Ruby client for the Ipregistry IP geolocation and threat data API
62
+ test_files: []