minfraud 1.1.0 → 1.5.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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rubocop.yml +12 -0
  3. data/.github/workflows/test.yml +33 -0
  4. data/.rubocop.yml +108 -0
  5. data/CHANGELOG.md +57 -0
  6. data/Gemfile +4 -2
  7. data/README.dev.md +1 -1
  8. data/README.md +170 -55
  9. data/Rakefile +9 -3
  10. data/bin/console +4 -3
  11. data/lib/maxmind/geoip2/model/city.rb +3 -3
  12. data/lib/maxmind/geoip2/model/country.rb +5 -5
  13. data/lib/maxmind/geoip2/record/traits.rb +13 -4
  14. data/lib/minfraud.rb +44 -6
  15. data/lib/minfraud/assessments.rb +113 -53
  16. data/lib/minfraud/components/account.rb +31 -9
  17. data/lib/minfraud/components/addressable.rb +73 -26
  18. data/lib/minfraud/components/base.rb +26 -14
  19. data/lib/minfraud/components/billing.rb +5 -0
  20. data/lib/minfraud/components/credit_card.rb +64 -20
  21. data/lib/minfraud/components/custom_inputs.rb +14 -3
  22. data/lib/minfraud/components/device.rb +45 -15
  23. data/lib/minfraud/components/email.rb +120 -9
  24. data/lib/minfraud/components/event.rb +60 -24
  25. data/lib/minfraud/components/order.rb +59 -22
  26. data/lib/minfraud/components/payment.rb +44 -9
  27. data/lib/minfraud/components/report/transaction.rb +50 -39
  28. data/lib/minfraud/components/shipping.rb +14 -5
  29. data/lib/minfraud/components/shopping_cart.rb +19 -12
  30. data/lib/minfraud/components/shopping_cart_item.rb +42 -13
  31. data/lib/minfraud/enum.rb +22 -8
  32. data/lib/minfraud/error_handler.rb +32 -25
  33. data/lib/minfraud/errors.rb +22 -2
  34. data/lib/minfraud/http_service.rb +23 -8
  35. data/lib/minfraud/http_service/request.rb +19 -18
  36. data/lib/minfraud/http_service/response.rb +19 -14
  37. data/lib/minfraud/model/address.rb +4 -4
  38. data/lib/minfraud/model/credit_card.rb +7 -7
  39. data/lib/minfraud/model/device.rb +2 -2
  40. data/lib/minfraud/model/email.rb +4 -4
  41. data/lib/minfraud/model/error.rb +1 -1
  42. data/lib/minfraud/model/insights.rb +5 -5
  43. data/lib/minfraud/model/ip_address.rb +20 -1
  44. data/lib/minfraud/model/ip_risk_reason.rb +48 -0
  45. data/lib/minfraud/model/issuer.rb +3 -3
  46. data/lib/minfraud/model/score.rb +6 -6
  47. data/lib/minfraud/model/shipping_address.rb +1 -1
  48. data/lib/minfraud/model/subscores.rb +38 -16
  49. data/lib/minfraud/model/warning.rb +2 -2
  50. data/lib/minfraud/report.rb +33 -13
  51. data/lib/minfraud/resolver.rb +25 -17
  52. data/lib/minfraud/validates.rb +187 -0
  53. data/lib/minfraud/version.rb +4 -1
  54. data/minfraud.gemspec +8 -2
  55. metadata +77 -10
  56. data/.travis.yml +0 -22
data/Rakefile CHANGED
@@ -1,6 +1,12 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
3
6
 
4
7
  RSpec::Core::RakeTask.new(:spec)
5
8
 
6
- task :default => :spec
9
+ RuboCop::RakeTask.new
10
+
11
+ task default: :spec
12
+ task default: :rubocop
data/bin/console CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require "bundler/setup"
4
- require "minfraud"
4
+ require 'bundler/setup'
5
+ require 'minfraud'
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +11,5 @@ require "minfraud"
10
11
  # require "pry"
11
12
  # Pry.start
12
13
 
13
- require "irb"
14
+ require 'irb'
14
15
  IRB.start
@@ -68,9 +68,9 @@ module MaxMind
68
68
  # @!visibility private
69
69
  def initialize(record, locales)
70
70
  super(record, locales)
71
- @city = MaxMind::GeoIP2::Record::City.new(record['city'], locales)
72
- @location = MaxMind::GeoIP2::Record::Location.new(record['location'])
73
- @postal = MaxMind::GeoIP2::Record::Postal.new(record['postal'])
71
+ @city = MaxMind::GeoIP2::Record::City.new(record['city'], locales)
72
+ @location = MaxMind::GeoIP2::Record::Location.new(record['location'])
73
+ @postal = MaxMind::GeoIP2::Record::Postal.new(record['postal'])
74
74
  @subdivisions = create_subdivisions(record['subdivisions'], locales)
75
75
  end
76
76
 
@@ -69,16 +69,16 @@ module MaxMind
69
69
 
70
70
  # @!visibility private
71
71
  def initialize(record, locales)
72
- @continent = MaxMind::GeoIP2::Record::Continent.new(
72
+ @continent = MaxMind::GeoIP2::Record::Continent.new(
73
73
  record['continent'],
74
74
  locales,
75
75
  )
76
- @country = MaxMind::GeoIP2::Record::Country.new(
76
+ @country = MaxMind::GeoIP2::Record::Country.new(
77
77
  record['country'],
78
78
  locales,
79
79
  )
80
- @maxmind = MaxMind::GeoIP2::Record::MaxMind.new(record['maxmind'])
81
- @registered_country = MaxMind::GeoIP2::Record::Country.new(
80
+ @maxmind = MaxMind::GeoIP2::Record::MaxMind.new(record['maxmind'])
81
+ @registered_country = MaxMind::GeoIP2::Record::Country.new(
82
82
  record['registered_country'],
83
83
  locales,
84
84
  )
@@ -86,7 +86,7 @@ module MaxMind
86
86
  record['represented_country'],
87
87
  locales,
88
88
  )
89
- @traits = MaxMind::GeoIP2::Record::Traits.new(record['traits'])
89
+ @traits = MaxMind::GeoIP2::Record::Traits.new(record['traits'])
90
90
  end
91
91
  end
92
92
  end
@@ -33,9 +33,9 @@ module MaxMind
33
33
  # @!visibility private
34
34
  def initialize(record)
35
35
  super(record)
36
- if !record.key?('network') && record.key?('ip_address') &&
36
+ if record && !record.key?('network') && record.key?('ip_address') &&
37
37
  record.key?('prefix_length')
38
- ip = IPAddr.new(record['ip_address']).mask(record['prefix_length'])
38
+ ip = IPAddr.new(record['ip_address']).mask(record['prefix_length'])
39
39
  # We could use ip.prefix instead of record['prefix_length'], but that
40
40
  # method only becomes available in Ruby 2.5+.
41
41
  record['network'] = format('%s/%d', ip.to_s, record['prefix_length'])
@@ -89,7 +89,7 @@ module MaxMind
89
89
  # NAT, this may differ from the IP address locally assigned to it. This
90
90
  # attribute is returned by all end points.
91
91
  #
92
- # @return [String]
92
+ # @return [String, nil]
93
93
  def ip_address
94
94
  get('ip_address')
95
95
  end
@@ -139,6 +139,15 @@ module MaxMind
139
139
  get('is_public_proxy')
140
140
  end
141
141
 
142
+ # This is true if the IP address is on a suspected anonymizing network
143
+ # and belongs to a residential ISP. This property is only available
144
+ # from GeoIP2 Precision Insights.
145
+ #
146
+ # @return [Boolean]
147
+ def residential_proxy?
148
+ get('is_residential_proxy')
149
+ end
150
+
142
151
  # This is true if the IP address is a Tor exit node. This property is only
143
152
  # available from GeoIP2 Precision Insights.
144
153
  #
@@ -160,7 +169,7 @@ module MaxMind
160
169
  # this is the largest network where all of the fields besides ip_address
161
170
  # have the same value.
162
171
  #
163
- # @return [String]
172
+ # @return [String, nil]
164
173
  def network
165
174
  get('network')
166
175
  end
data/lib/minfraud.rb CHANGED
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
1
4
  require 'minfraud'
2
5
  require 'minfraud/enum'
6
+ require 'minfraud/validates'
3
7
  require 'minfraud/components/base'
4
8
  require 'minfraud/components/account'
5
9
  require 'minfraud/components/addressable'
@@ -25,22 +29,56 @@ require 'minfraud/error_handler'
25
29
  require 'minfraud/assessments'
26
30
  require 'minfraud/report'
27
31
 
32
+ # This class holds global configuration parameters and provides a namespace
33
+ # for the gem's classes.
28
34
  module Minfraud
29
35
  class << self
30
- # @!attribute user_id
31
- # @return [String] MaxMind account ID that is used for authorization
36
+ # The MaxMind account ID that is used for authorization.
37
+ #
38
+ # @return [Integer, nil]
39
+ attr_accessor :account_id
40
+
41
+ # Enable client side validation. This is disabled by default.
42
+ #
43
+ # @return [Boolean, nil]
44
+ attr_accessor :enable_validation
45
+
46
+ # The host to use when connecting to the web service.
47
+ #
48
+ # @return [String, nil]
49
+ attr_accessor :host
50
+
51
+ # The MaxMind account ID that is used for authorization.
52
+ #
53
+ # @deprecated Use {::account_id} instead. This will be removed in the next
54
+ # major version.
55
+ #
56
+ # @return [Integer, nil]
32
57
  attr_accessor :user_id
33
58
 
34
- # @!attribute license_key
35
- # @return [String] MaxMind license key that is used for authorization
59
+ # The MaxMind license key that is used for authorization.
60
+ #
61
+ # @return [String, nil]
36
62
  attr_accessor :license_key
37
63
 
38
- # @yield [self] to accept configuration settings
64
+ # @!visibility private
65
+ attr_reader :connection
66
+
67
+ # Yield self to accept configuration settings.
68
+ #
69
+ # @yield [self]
39
70
  def configure
40
71
  yield self
72
+
73
+ config = Minfraud::HTTPService.configuration
74
+ @connection = Faraday.new(config[:server], {}, &config[:middleware])
41
75
  end
42
76
 
43
- # @return [Hash] current Minfraud configuration
77
+ # The current Minfraud configuration.
78
+ #
79
+ # @deprecated This will be removed in the next major version.
80
+ #
81
+ # @return [Hash]
44
82
  def configuration
45
83
  {
46
84
  user_id: @user_id,
@@ -1,56 +1,76 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Minfraud
4
+ # Assessments is used to perform minFraud Score, Insights, and Factors
5
+ # requests.
6
+ #
7
+ # @see https://dev.maxmind.com/minfraud/
2
8
  class Assessments
3
9
  include ::Minfraud::HTTPService
4
10
  include ::Minfraud::Resolver
5
11
 
6
- # @attribute account
7
- # @return [Minfraud::Components::Account] Account component
12
+ # The Account component.
13
+ #
14
+ # @return [Minfraud::Components::Account, nil]
8
15
  attr_accessor :account
9
16
 
10
- # @attribute billing
11
- # @return [Minfraud::Components::Billing] Billing component
17
+ # The Billing component.
18
+ #
19
+ # @return [Minfraud::Components::Billing, nil]
12
20
  attr_accessor :billing
13
21
 
14
- # @attribute credit_card
15
- # @return [Minfraud::Components::CreditCard] CreditCard component
22
+ # The CreditCard component.
23
+ #
24
+ # @return [Minfraud::Components::CreditCard, nil]
16
25
  attr_accessor :credit_card
17
26
 
18
- # @attribute custom_inputs
19
- # @return [Minfraud::Components::CustomInputs] CustomInputs component
27
+ # The CustomInputs component.
28
+ #
29
+ # @return [Minfraud::Components::CustomInputs, nil]
20
30
  attr_accessor :custom_inputs
21
31
 
22
- # @attribute device
23
- # @return [Minfraud::Components::Device] Device component
32
+ # The Device component.
33
+ #
34
+ # @return [Minfraud::Components::Device, nil]
24
35
  attr_accessor :device
25
36
 
26
- # @attribute email
27
- # @return [Minfraud::Components::Email] Email component
37
+ # The Email component.
38
+ #
39
+ # @return [Minfraud::Components::Email, nil]
28
40
  attr_accessor :email
29
41
 
30
- # @attribute event
31
- # @return [Minfraud::Components::Event] Event component
42
+ # The Event component.
43
+ #
44
+ # @return [Minfraud::Components::Event, nil]
32
45
  attr_accessor :event
33
46
 
34
- # @attribute order
35
- # @return [Minfraud::Components::Order] Order component
47
+ # The Order component.
48
+ #
49
+ # @return [Minfraud::Components::Order, nil]
36
50
  attr_accessor :order
37
51
 
38
- # @attribute payment
39
- # @return [Minfraud::Components::Payment] Payment component
52
+ # The Payment component.
53
+ #
54
+ # @return [Minfraud::Components::Payment, nil]
40
55
  attr_accessor :payment
41
56
 
42
- # @!attribute shipping
43
- # @return [Minfraud::Components::Shipping] Shipping component
57
+ # The Shipping component.
58
+ #
59
+ # @return [Minfraud::Components::Shipping, nil]
44
60
  attr_accessor :shipping
45
61
 
46
- # @!attribute shopping_cart
47
- # @return [Minfraud::Components::ShoppingCart] ShoppingCart component
62
+ # The ShoppingCart component.
63
+ #
64
+ # @return [Minfraud::Components::ShoppingCart, nil]
48
65
  attr_accessor :shopping_cart
49
66
 
50
- # @param [Hash] params hash of parameters
51
- # @param [Minfraud::Resolver] resolver resolver that maps params to components
52
- # @note In case when params is a Hash of components it just assigns them to the corresponding instance variables
53
- # @return [Minfraud::Assessments] Assessments instance
67
+ # @param params [Hash] Hash of parameters. Each key is a symbol
68
+ # corresponding to one of the available component attributes. Values may
69
+ # be component objects or hashes that will be provided to the component
70
+ # constructors.
71
+ #
72
+ # @param resolver [Minfraud::Resolver] Resolver that maps parameters to
73
+ # components.
54
74
  def initialize(params = {}, resolver = ::Minfraud::Resolver)
55
75
  @locales = params.delete('locales')
56
76
  @locales = ['en'] if @locales.nil?
@@ -58,42 +78,82 @@ module Minfraud
58
78
  resolver.assign(self, params)
59
79
  end
60
80
 
61
- # @!macro [attach] define
62
- # @method $1
63
- # Makes a request to minFraud $1 endpoint.
64
- # Raises an error in case of invalid response
65
- # @return [Minfraud::HTTPService::Response] Wrapped minFraud response
66
- def self.define(endpoint)
67
- define_method(endpoint) do
68
- raw = request.perform(verb: :post, endpoint: endpoint.to_s, body: request_body)
69
- response = ::Minfraud::HTTPService::Response.new(
70
- endpoint: endpoint,
71
- locales: @locales,
72
- status: raw.status.to_i,
73
- body: raw.body,
74
- headers: raw.headers
75
- )
76
-
77
- ::Minfraud::ErrorHandler.examine(response)
78
- end
81
+ # Perform a minFraud Factors request.
82
+ #
83
+ # @return [Minfraud::HTTPService::Response]
84
+ #
85
+ # @raise [Minfraud::AuthorizationError] If there was an authentication
86
+ # problem.
87
+ #
88
+ # @raise [Minfraud::ClientError] If there was a critical problem with one
89
+ # of your inputs.
90
+ #
91
+ # @raise [Minfraud::ServerError] If the server reported an error of some
92
+ # kind.
93
+ def factors
94
+ perform_request(:factors)
79
95
  end
80
96
 
81
- define :score
82
- define :insights
83
- define :factors
97
+ # Perform a minFraud Insights request.
98
+ #
99
+ # @return [Minfraud::HTTPService::Response]
100
+ #
101
+ # @raise [Minfraud::AuthorizationError] If there was an authentication
102
+ # problem.
103
+ #
104
+ # @raise [Minfraud::ClientError] If there was a critical problem with one
105
+ # of your inputs.
106
+ #
107
+ # @raise [Minfraud::ServerError] If the server reported an error of some
108
+ # kind.
109
+ def insights
110
+ perform_request(:insights)
111
+ end
112
+
113
+ # Perform a minFraud Score request.
114
+ #
115
+ # @return [Minfraud::HTTPService::Response]
116
+ #
117
+ # @raise [Minfraud::AuthorizationError] If there was an authentication
118
+ # problem.
119
+ #
120
+ # @raise [Minfraud::ClientError] If there was a critical problem with one
121
+ # of your inputs.
122
+ #
123
+ # @raise [Minfraud::ServerError] If the server reported an error of some
124
+ # kind.
125
+ def score
126
+ perform_request(:score)
127
+ end
84
128
 
85
129
  private
86
- # Creates a unified request body from components converted to JSON
87
- # @return [Hash] Request body
130
+
131
+ def perform_request(endpoint)
132
+ raw = request.perform(
133
+ verb: :post,
134
+ endpoint: endpoint.to_s,
135
+ body: request_body,
136
+ )
137
+
138
+ response = ::Minfraud::HTTPService::Response.new(
139
+ endpoint: endpoint,
140
+ locales: @locales,
141
+ status: raw.status.to_i,
142
+ body: raw.body,
143
+ headers: raw.headers
144
+ )
145
+
146
+ ::Minfraud::ErrorHandler.examine(response)
147
+ end
148
+
88
149
  def request_body
89
- MAPPING.keys.inject({}) do |mem, e|
90
- next mem unless value = send(e)
150
+ MAPPING.keys.reduce({}) do |mem, e|
151
+ next mem unless (value = send(e))
152
+
91
153
  mem.merge!(e.to_s => value.to_json)
92
154
  end
93
155
  end
94
156
 
95
- # Creates memoized Minfraud::HTTPService::Request instance
96
- # @return [Minfraud::HTTPService::Request] Request instance based on configuration params
97
157
  def request
98
158
  @request ||= Request.new(::Minfraud::HTTPService.configuration)
99
159
  end
@@ -1,22 +1,44 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Minfraud
2
4
  module Components
5
+ # Account corresponds to the account object of a minFraud request.
6
+ #
7
+ # @see https://dev.maxmind.com/minfraud/#Account_(/account)
3
8
  class Account < Base
4
- # @attribute user_id
5
- # @return [String] A unique user ID associated with the end-user in your system.
6
- # 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
+ include Minfraud::Validates
10
+
11
+ # A unique user ID associated with the end-user in your system. If your
12
+ # system allows the login name for the account to be changed, this should
13
+ # not be the login name for the account, but rather should be an internal
14
+ # ID that does not change. This is not your MaxMind account ID. No
15
+ # specific format is required.
16
+ #
17
+ # @return [String, nil]
8
18
  attr_accessor :user_id
9
19
 
10
- # @attribute username_md5
11
- # @return [String] An MD5 hash as a hexadecimal string of the username or login name associated with the account
20
+ # An MD5 hash as a hexadecimal string of the username or login name
21
+ # associated with the account.
22
+ #
23
+ # @return [String, nil]
12
24
  attr_accessor :username_md5
13
25
 
14
- # Creates Minfraud::Components::Account instance
15
- # @param [Hash] params hash of parameters
16
- # @return [Minfraud::Components::Account] an Account instance
26
+ # @param params [Hash] Hash of parameters. Each key/value should
27
+ # correspond to one of the available attributes.
17
28
  def initialize(params = {})
18
29
  @user_id = params[:user_id]
19
30
  @username_md5 = params[:username_md5]
31
+
32
+ validate
33
+ end
34
+
35
+ private
36
+
37
+ def validate
38
+ return if !Minfraud.enable_validation
39
+
40
+ validate_string('user_id', 255, @user_id)
41
+ validate_md5('username_md5', @username_md5)
20
42
  end
21
43
  end
22
44
  end