minfraud 1.0.1 → 1.2.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.
Files changed (74) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/test.yml +46 -0
  3. data/.gitignore +2 -0
  4. data/.rubocop.yml +127 -0
  5. data/.travis.yml +20 -3
  6. data/CHANGELOG.md +56 -0
  7. data/CODE_OF_CONDUCT.md +4 -4
  8. data/Gemfile +11 -2
  9. data/LICENSE.txt +2 -1
  10. data/README.dev.md +4 -0
  11. data/README.md +107 -36
  12. data/Rakefile +18 -3
  13. data/bin/console +4 -3
  14. data/lib/maxmind/geoip2/model/city.rb +99 -0
  15. data/lib/maxmind/geoip2/model/country.rb +94 -0
  16. data/lib/maxmind/geoip2/model/insights.rb +38 -0
  17. data/lib/maxmind/geoip2/record/abstract.rb +46 -0
  18. data/lib/maxmind/geoip2/record/city.rb +62 -0
  19. data/lib/maxmind/geoip2/record/continent.rb +61 -0
  20. data/lib/maxmind/geoip2/record/country.rb +78 -0
  21. data/lib/maxmind/geoip2/record/location.rb +97 -0
  22. data/lib/maxmind/geoip2/record/maxmind.rb +41 -0
  23. data/lib/maxmind/geoip2/record/place.rb +52 -0
  24. data/lib/maxmind/geoip2/record/postal.rb +54 -0
  25. data/lib/maxmind/geoip2/record/represented_country.rb +47 -0
  26. data/lib/maxmind/geoip2/record/subdivision.rb +72 -0
  27. data/lib/maxmind/geoip2/record/traits.rb +224 -0
  28. data/lib/minfraud.rb +33 -8
  29. data/lib/minfraud/assessments.rb +25 -10
  30. data/lib/minfraud/components/account.rb +3 -1
  31. data/lib/minfraud/components/addressable.rb +11 -9
  32. data/lib/minfraud/components/base.rb +29 -5
  33. data/lib/minfraud/components/billing.rb +2 -0
  34. data/lib/minfraud/components/credit_card.rb +8 -1
  35. data/lib/minfraud/components/custom_inputs.rb +16 -0
  36. data/lib/minfraud/components/device.rb +13 -0
  37. data/lib/minfraud/components/email.rb +2 -0
  38. data/lib/minfraud/components/event.rb +15 -8
  39. data/lib/minfraud/components/order.rb +4 -1
  40. data/lib/minfraud/components/payment.rb +138 -14
  41. data/lib/minfraud/components/report/transaction.rb +69 -0
  42. data/lib/minfraud/components/shipping.rb +2 -4
  43. data/lib/minfraud/components/shopping_cart.rb +4 -1
  44. data/lib/minfraud/components/shopping_cart_item.rb +2 -2
  45. data/lib/minfraud/enum.rb +7 -4
  46. data/lib/minfraud/error_handler.rb +29 -9
  47. data/lib/minfraud/errors.rb +2 -0
  48. data/lib/minfraud/http_service.rb +13 -4
  49. data/lib/minfraud/http_service/request.rb +4 -1
  50. data/lib/minfraud/http_service/response.rb +40 -6
  51. data/lib/minfraud/model/abstract.rb +20 -0
  52. data/lib/minfraud/model/address.rb +52 -0
  53. data/lib/minfraud/model/billing_address.rb +11 -0
  54. data/lib/minfraud/model/credit_card.rb +75 -0
  55. data/lib/minfraud/model/device.rb +54 -0
  56. data/lib/minfraud/model/disposition.rb +35 -0
  57. data/lib/minfraud/model/email.rb +54 -0
  58. data/lib/minfraud/model/email_domain.rb +24 -0
  59. data/lib/minfraud/model/error.rb +28 -0
  60. data/lib/minfraud/model/factors.rb +24 -0
  61. data/lib/minfraud/model/geoip2_location.rb +25 -0
  62. data/lib/minfraud/model/insights.rb +68 -0
  63. data/lib/minfraud/model/ip_address.rb +82 -0
  64. data/lib/minfraud/model/issuer.rb +49 -0
  65. data/lib/minfraud/model/score.rb +76 -0
  66. data/lib/minfraud/model/score_ip_address.rb +23 -0
  67. data/lib/minfraud/model/shipping_address.rb +30 -0
  68. data/lib/minfraud/model/subscores.rb +175 -0
  69. data/lib/minfraud/model/warning.rb +63 -0
  70. data/lib/minfraud/report.rb +40 -0
  71. data/lib/minfraud/resolver.rb +16 -13
  72. data/lib/minfraud/version.rb +3 -1
  73. data/minfraud.gemspec +21 -15
  74. metadata +84 -19
@@ -0,0 +1,224 @@
1
+ # Copyright (c) 2020 by MaxMind, Inc.
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ # frozen_string_literal: true
22
+
23
+ require 'ipaddr'
24
+ require 'maxmind/geoip2/record/abstract'
25
+
26
+ module MaxMind
27
+ module GeoIP2
28
+ module Record
29
+ # Contains data for the traits record associated with an IP address.
30
+ #
31
+ # This record is returned by all location services and databases.
32
+ class Traits < Abstract
33
+ # @!visibility private
34
+ def initialize(record)
35
+ super(record)
36
+ if !record.key?('network') && record.key?('ip_address') &&
37
+ record.key?('prefix_length')
38
+ ip = IPAddr.new(record['ip_address']).mask(record['prefix_length'])
39
+ # We could use ip.prefix instead of record['prefix_length'], but that
40
+ # method only becomes available in Ruby 2.5+.
41
+ record['network'] = format('%s/%d', ip.to_s, record['prefix_length'])
42
+ end
43
+ end
44
+
45
+ # The autonomous system number associated with the IP address. See
46
+ # Wikipedia[https://en.wikipedia.org/wiki/Autonomous_system_(Internet)].
47
+ # This attribute is only available from the City and Insights web service
48
+ # and the GeoIP2 Enterprise database.
49
+ #
50
+ # @return [Integer, nil]
51
+ def autonomous_system_number
52
+ get('autonomous_system_number')
53
+ end
54
+
55
+ # The organization associated with the registered autonomous system number
56
+ # for the IP address. See
57
+ # Wikipedia[https://en.wikipedia.org/wiki/Autonomous_system_(Internet)].
58
+ # This attribute is only available from the City and Insights web service
59
+ # and the GeoIP2 Enterprise database.
60
+ #
61
+ # @return [String, nil]
62
+ def autonomous_system_organization
63
+ get('autonomous_system_organization')
64
+ end
65
+
66
+ # The connection type may take the following values: "Dialup",
67
+ # "Cable/DSL", "Corporate", "Cellular". Additional values may be added in
68
+ # the future. This attribute is only available in the GeoIP2 Enterprise
69
+ # database.
70
+ #
71
+ # @return [String, nil]
72
+ def connection_type
73
+ get('connection_type')
74
+ end
75
+
76
+ # The second level domain associated with the IP address. This will be
77
+ # something like "example.com" or "example.co.uk", not "foo.example.com".
78
+ # This attribute is only available from the City and Insights web service
79
+ # and the GeoIP2 Enterprise database.
80
+ #
81
+ # @return [String, nil]
82
+ def domain
83
+ get('domain')
84
+ end
85
+
86
+ # The IP address that the data in the model is for. If you performed a "me"
87
+ # lookup against the web service, this will be the externally routable IP
88
+ # address for the system the code is running on. If the system is behind a
89
+ # NAT, this may differ from the IP address locally assigned to it. This
90
+ # attribute is returned by all end points.
91
+ #
92
+ # @return [String]
93
+ def ip_address
94
+ get('ip_address')
95
+ end
96
+
97
+ # This is true if the IP address belongs to any sort of anonymous network.
98
+ # This property is only available from GeoIP2 Precision Insights.
99
+ #
100
+ # @return [Boolean]
101
+ def anonymous?
102
+ get('is_anonymous')
103
+ end
104
+
105
+ # This is true if the IP address is registered to an anonymous VPN
106
+ # provider. If a VPN provider does not register subnets under names
107
+ # associated with them, we will likely only flag their IP ranges using the
108
+ # hosting_provider? property. This property is only available from GeoIP2
109
+ # Precision Insights.
110
+ #
111
+ # @return [Boolean]
112
+ def anonymous_vpn?
113
+ get('is_anonymous_vpn')
114
+ end
115
+
116
+ # This is true if the IP address belongs to a hosting or VPN provider (see
117
+ # description of the anonymous_vpn? property). This property is only
118
+ # available from GeoIP2 Precision Insights.
119
+ #
120
+ # @return [Boolean]
121
+ def hosting_provider?
122
+ get('is_hosting_provider')
123
+ end
124
+
125
+ # This attribute is true if MaxMind believes this IP address to be a
126
+ # legitimate proxy, such as an internal VPN used by a corporation. This
127
+ # attribute is only available in the GeoIP2 Enterprise database.
128
+ #
129
+ # @return [Boolean]
130
+ def legitimate_proxy?
131
+ get('is_legitimate_proxy')
132
+ end
133
+
134
+ # This is true if the IP address belongs to a public proxy. This property
135
+ # is only available from GeoIP2 Precision Insights.
136
+ #
137
+ # @return [Boolean]
138
+ def public_proxy?
139
+ get('is_public_proxy')
140
+ end
141
+
142
+ # This is true if the IP address is a Tor exit node. This property is only
143
+ # available from GeoIP2 Precision Insights.
144
+ #
145
+ # @return [Boolean]
146
+ def tor_exit_node?
147
+ get('is_tor_exit_node')
148
+ end
149
+
150
+ # The name of the ISP associated with the IP address. This attribute is
151
+ # only available from the City and Insights web services and the GeoIP2
152
+ # Enterprise database.
153
+ #
154
+ # @return [String, nil]
155
+ def isp
156
+ get('isp')
157
+ end
158
+
159
+ # The network in CIDR notation associated with the record. In particular,
160
+ # this is the largest network where all of the fields besides ip_address
161
+ # have the same value.
162
+ #
163
+ # @return [String]
164
+ def network
165
+ get('network')
166
+ end
167
+
168
+ # The name of the organization associated with the IP address. This
169
+ # attribute is only available from the City and Insights web services and
170
+ # the GeoIP2 Enterprise database.
171
+ #
172
+ # @return [String, nil]
173
+ def organization
174
+ get('organization')
175
+ end
176
+
177
+ # An indicator of how static or dynamic an IP address is. This property is
178
+ # only available from GeoIP2 Precision Insights.
179
+ #
180
+ # @return [Float, nil]
181
+ def static_ip_score
182
+ get('static_ip_score')
183
+ end
184
+
185
+ # The estimated number of users sharing the IP/network during the past 24
186
+ # hours. For IPv4, the count is for the individual IP. For IPv6, the count
187
+ # is for the /64 network. This property is only available from GeoIP2
188
+ # Precision Insights.
189
+ #
190
+ # @return [Integer, nil]
191
+ def user_count
192
+ get('user_count')
193
+ end
194
+
195
+ # The user type associated with the IP address. This can be one of the
196
+ # following values:
197
+ #
198
+ # * business
199
+ # * cafe
200
+ # * cellular
201
+ # * college
202
+ # * content_delivery_network
203
+ # * dialup
204
+ # * government
205
+ # * hosting
206
+ # * library
207
+ # * military
208
+ # * residential
209
+ # * router
210
+ # * school
211
+ # * search_engine_spider
212
+ # * traveler
213
+ #
214
+ # This attribute is only available from the Insights web service and the
215
+ # GeoIP2 Enterprise database.
216
+ #
217
+ # @return [String, nil]
218
+ def user_type
219
+ get('user_type')
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'minfraud'
2
4
  require 'minfraud/enum'
3
5
  require 'minfraud/components/base'
@@ -5,15 +7,16 @@ require 'minfraud/components/account'
5
7
  require 'minfraud/components/addressable'
6
8
  require 'minfraud/components/billing'
7
9
  require 'minfraud/components/credit_card'
10
+ require 'minfraud/components/custom_inputs'
8
11
  require 'minfraud/components/device'
9
12
  require 'minfraud/components/email'
10
13
  require 'minfraud/components/event'
11
14
  require 'minfraud/components/order'
12
15
  require 'minfraud/components/payment'
13
- require 'minfraud/components/shopping_cart_item'
16
+ require 'minfraud/components/report/transaction'
14
17
  require 'minfraud/components/shipping'
15
18
  require 'minfraud/components/shopping_cart'
16
- require 'minfraud/components/device'
19
+ require 'minfraud/components/shopping_cart_item'
17
20
  require 'minfraud/resolver'
18
21
  require 'minfraud/version'
19
22
  require 'minfraud/errors'
@@ -22,23 +25,45 @@ require 'minfraud/http_service/request'
22
25
  require 'minfraud/http_service/response'
23
26
  require 'minfraud/error_handler'
24
27
  require 'minfraud/assessments'
28
+ require 'minfraud/report'
25
29
 
26
30
  module Minfraud
27
31
  class << self
28
- # @!attribute user_id
29
- # @return [String] MaxMind username that is used for authorization
32
+ # The MaxMind account ID that is used for authorization.
33
+ #
34
+ # @return [Integer, nil]
35
+ attr_accessor :account_id
36
+
37
+ # The host to use when connecting to the web service.
38
+ #
39
+ # @return [String, nil]
40
+ attr_accessor :host
41
+
42
+ # The MaxMind account ID that is used for authorization.
43
+ #
44
+ # @deprecated Use {::account_id} instead. This will be removed in the next
45
+ # major version.
46
+ #
47
+ # @return [Integer, nil]
30
48
  attr_accessor :user_id
31
49
 
32
- # @!attribute license_key
33
- # @return [String] MaxMind license key that is used for authorization
50
+ # The MaxMind license key that is used for authorization.
51
+ #
52
+ # @return [String, nil]
34
53
  attr_accessor :license_key
35
54
 
36
- # @yield [self] to accept configuration settings
55
+ # Yield self to accept configuration settings.
56
+ #
57
+ # @yield [self]
37
58
  def configure
38
59
  yield self
39
60
  end
40
61
 
41
- # @return [Hash] current Minfraud configuration
62
+ # The current Minfraud configuration.
63
+ #
64
+ # @deprecated This will be removed in the next major version.
65
+ #
66
+ # @return [Hash]
42
67
  def configuration
43
68
  {
44
69
  user_id: @user_id,
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Minfraud
2
4
  class Assessments
3
5
  include ::Minfraud::HTTPService
@@ -15,6 +17,10 @@ module Minfraud
15
17
  # @return [Minfraud::Components::CreditCard] CreditCard component
16
18
  attr_accessor :credit_card
17
19
 
20
+ # @attribute custom_inputs
21
+ # @return [Minfraud::Components::CustomInputs] CustomInputs component
22
+ attr_accessor :custom_inputs
23
+
18
24
  # @attribute device
19
25
  # @return [Minfraud::Components::Device] Device component
20
26
  attr_accessor :device
@@ -40,16 +46,18 @@ module Minfraud
40
46
  attr_accessor :shipping
41
47
 
42
48
  # @!attribute shopping_cart
43
- # @return [Minfraud::Components::ShoppingCarat] ShoppingCart component
49
+ # @return [Minfraud::Components::ShoppingCart] ShoppingCart component
44
50
  attr_accessor :shopping_cart
45
51
 
46
52
  # @param [Hash] params hash of parameters
47
53
  # @param [Minfraud::Resolver] resolver resolver that maps params to components
48
- # In case if params is a Hash of components it just assignes them to corresponding
49
- # instance variables
54
+ # @note In case when params is a Hash of components it just assigns them to the corresponding instance variables
50
55
  # @return [Minfraud::Assessments] Assessments instance
51
56
  def initialize(params = {}, resolver = ::Minfraud::Resolver)
52
- resolver.assign(context: self, params: params)
57
+ @locales = params.delete('locales')
58
+ @locales = ['en'] if @locales.nil?
59
+
60
+ resolver.assign(self, params)
53
61
  end
54
62
 
55
63
  # @!macro [attach] define
@@ -59,14 +67,16 @@ module Minfraud
59
67
  # @return [Minfraud::HTTPService::Response] Wrapped minFraud response
60
68
  def self.define(endpoint)
61
69
  define_method(endpoint) do
62
- raw = request.perform(verb: :post, endpoint: endpoint, body: request_body)
70
+ raw = request.perform(verb: :post, endpoint: endpoint.to_s, body: request_body)
63
71
  response = ::Minfraud::HTTPService::Response.new(
64
- status: raw.status.to_i,
65
- body: raw.body,
66
- headers: raw.headers
72
+ endpoint: endpoint,
73
+ locales: @locales,
74
+ status: raw.status.to_i,
75
+ body: raw.body,
76
+ headers: raw.headers
67
77
  )
68
78
 
69
- ::Minfraud::ErrorHandler.inspect(response)
79
+ ::Minfraud::ErrorHandler.examine(response)
70
80
  end
71
81
  end
72
82
 
@@ -75,10 +85,15 @@ module Minfraud
75
85
  define :factors
76
86
 
77
87
  private
88
+
78
89
  # Creates a unified request body from components converted to JSON
79
90
  # @return [Hash] Request body
80
91
  def request_body
81
- MAPPING.keys.inject({}) { |mem, e| mem.merge!(e.to_s => send(e)&.to_json) }
92
+ MAPPING.keys.reduce({}) do |mem, e|
93
+ next mem unless (value = send(e))
94
+
95
+ mem.merge!(e.to_s => value.to_json)
96
+ end
82
97
  end
83
98
 
84
99
  # Creates memoized Minfraud::HTTPService::Request instance
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Minfraud
2
4
  module Components
3
5
  class Account < Base
4
6
  # @attribute user_id
5
7
  # @return [String] A unique user ID associated with the end-user in your system.
6
8
  # If your system allows the login name for the account to be changed, this should not be the login name for the account,
7
- # but rather should be an internal ID that does not change. This is not your MaxMind user ID
9
+ # but rather should be an internal ID that does not change. This is not your MaxMind user ID.
8
10
  attr_accessor :user_id
9
11
 
10
12
  # @attribute username_md5
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Minfraud
2
4
  module Components
3
5
  class Addressable < Base
@@ -14,39 +16,39 @@ module Minfraud
14
16
  attr_accessor :company
15
17
 
16
18
  # @attribute address
17
- # @return [String] The first line of the users billing / shipping address
19
+ # @return [String] The first line of the user's billing / shipping address
18
20
  attr_accessor :address
19
21
 
20
22
  # @attribute address_2
21
- # @return [String] The second line of the users billing / shipping address
23
+ # @return [String] The second line of the user's billing / shipping address
22
24
  attr_accessor :address_2
23
25
 
24
26
  # @attribute city
25
- # @return [String] The city of the users billing / shipping address
27
+ # @return [String] The city of the user's billing / shipping address
26
28
  attr_accessor :city
27
29
 
28
30
  # @attribute region
29
- # @return [String] The ISO 3166-2 subdivision code for the users billing / shipping address
31
+ # @return [String] The ISO 3166-2 subdivision code for the user's billing / shipping address
30
32
  attr_accessor :region
31
33
 
32
34
  # @attribute country
33
- # @return [String] The two character ISO 3166-1 alpha-2 country code of the users billing / shipping address
35
+ # @return [String] The two character ISO 3166-1 alpha-2 country code of the user's billing / shipping address
34
36
  attr_accessor :country
35
37
 
36
38
  # @attribute postal
37
- # @return [String] The postal code of the users billing / shipping address
39
+ # @return [String] The postal code of the user's billing / shipping address
38
40
  attr_accessor :postal
39
41
 
40
42
  # @attribute phone_number
41
- # @return [String] The phone number without the country code for the users billing / shipping address
43
+ # @return [String] The phone number without the country code for the user's billing / shipping address
42
44
  attr_accessor :phone_number
43
45
 
44
46
  # @attribute phone_country_code
45
- # @return [String] The country code for phone number associated with the users billing / shipping address
47
+ # @return [String] The country code for phone number associated with the user's billing / shipping address
46
48
  attr_accessor :phone_country_code
47
49
 
48
50
  # Creates Minfraud::Components::Addressable instance
49
- # This class is used as a parent class for Billing and Shipping components
51
+ # @note This class is used as a parent class for Billing and Shipping components
50
52
  # @param [Hash] params hash of parameters
51
53
  # @return [Minfraud::Components::Addressable] an Addressable instance
52
54
  def initialize(params = {})
@@ -1,13 +1,37 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Minfraud
2
4
  module Components
3
- # Note: This class is used as a parent class for all other components
4
- # It defines a method which is used for basic JSON representation of PORO objects
5
+ # @note This class is used as a parent class for all other components
6
+ # @note It defines a method which is used for basic JSON representation of PORO objects
5
7
  class Base
6
8
  # @return [Hash] a JSON representation of component attributes
7
- def to_json
8
- instance_variables.inject({}) { |mem, e| mem.merge!(e.to_s.gsub(/@/, '') => instance_variable_get(e).to_s) }
9
- .delete_if { |_, v| v.empty? }
9
+ def to_json(*_args)
10
+ instance_variables.reduce({}) { |mem, e| populate!(mem, e) }
10
11
  end
12
+
13
+ private
14
+
15
+ # @note This method may modify passed hash. Non-existing instance variables are ignored
16
+ # @param [Hash] hash an accumulator
17
+ # @param [Symbol] v_sym an instance variable symbol
18
+ # @return [Hash] a hash containing a JSON representation of instance variable name and it's value
19
+ def populate!(hash, v_sym)
20
+ return hash unless (value = instance_variable_get(v_sym))
21
+
22
+ key = v_sym.to_s.gsub(/@/, '')
23
+ hash.merge!(key => represent(key, value))
24
+ end
25
+
26
+ # param [Symbol] key instance variable symbol
27
+ # param [Object] value instance variable value
28
+ # @return [Object] value representation according to the request format
29
+ def represent(key, value)
30
+ BOOLS.include?(key) ? value : value.to_s
31
+ end
32
+
33
+ # Keys that have to remain boolean
34
+ BOOLS = %w[was_authorized is_gift has_gift_message].freeze
11
35
  end
12
36
  end
13
37
  end