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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'minfraud/model/error'
2
4
  require 'minfraud/model/factors'
3
5
  require 'minfraud/model/insights'
@@ -5,24 +7,26 @@ require 'minfraud/model/score'
5
7
 
6
8
  module Minfraud
7
9
  module HTTPService
8
- # Response class for HTTP requests
10
+ # Response class for HTTP requests.
9
11
  class Response
10
- # @attribute status
11
- # @return [Integer] HTTP response status
12
+ # HTTP response status.
13
+ #
14
+ # @return [Integer, nil]
12
15
  attr_reader :status
13
16
 
14
- # @attribute body
17
+ # HTTP response model.
18
+ #
15
19
  # @return [Minfraud::Model::Score, Minfraud::Model::Insights,
16
- # Minfraud::Model::Factors] HTTP response body
20
+ # Minfraud::Model::Factors, nil]
17
21
  attr_reader :body
18
22
 
19
- # @attribute headers
20
- # @return [Hash] HTTP response headers
23
+ # HTTP response headers.
24
+ #
25
+ # @return [Hash, nil]
21
26
  attr_reader :headers
22
27
 
23
- # Creates Minfraud::HTTPService::Response instance
24
- # @param [Hash] params hash of parameters
25
- # @return [Minfraud::HTTPService::Response] Response instance
28
+ # @param params [Hash] Hash of parameters. +:status+, +:endpoint+,
29
+ # +:body+, +:locales+, and +:headers+ are used.
26
30
  def initialize(params = {})
27
31
  @status = params[:status]
28
32
  @body = make_body(
@@ -33,8 +37,9 @@ module Minfraud
33
37
  @headers = params[:headers]
34
38
  end
35
39
 
36
- # Returns minFraud-specific response code
37
- # @return [Symbol, nil] minFraud specific request code
40
+ # Return the minFraud-specific response code.
41
+ #
42
+ # @return [Symbol, nil]
38
43
  def code
39
44
  return nil if body.nil?
40
45
 
@@ -55,9 +60,9 @@ module Minfraud
55
60
  end
56
61
 
57
62
  ENDPOINT_TO_CLASS = {
58
- factors: Minfraud::Model::Factors,
63
+ factors: Minfraud::Model::Factors,
59
64
  insights: Minfraud::Model::Insights,
60
- score: Minfraud::Model::Score
65
+ score: Minfraud::Model::Score
61
66
  }.freeze
62
67
  end
63
68
  end
@@ -42,10 +42,10 @@ module Minfraud
42
42
  super(record)
43
43
 
44
44
  @distance_to_ip_location = get('distance_to_ip_location')
45
- @is_in_ip_country = get('is_in_ip_country')
46
- @is_postal_in_city = get('is_postal_in_city')
47
- @latitude = get('latitude')
48
- @longitude = get('longitude')
45
+ @is_in_ip_country = get('is_in_ip_country')
46
+ @is_postal_in_city = get('is_postal_in_city')
47
+ @latitude = get('latitude')
48
+ @longitude = get('longitude')
49
49
  end
50
50
  end
51
51
  end
@@ -59,16 +59,16 @@ module Minfraud
59
59
  def initialize(record)
60
60
  super(record)
61
61
 
62
- @brand = get('brand')
63
- @country = get('country')
64
- @is_business = get('is_business')
62
+ @brand = get('brand')
63
+ @country = get('country')
64
+ @is_business = get('is_business')
65
65
  @is_issued_in_billing_address_country = get(
66
66
  'is_issued_in_billing_address_country'
67
67
  )
68
- @is_prepaid = get('is_prepaid')
69
- @is_virtual = get('is_virtual')
70
- @issuer = Minfraud::Model::Issuer.new(get('issuer'))
71
- @type = get('type')
68
+ @is_prepaid = get('is_prepaid')
69
+ @is_virtual = get('is_virtual')
70
+ @issuer = Minfraud::Model::Issuer.new(get('issuer'))
71
+ @type = get('type')
72
72
  end
73
73
  end
74
74
  end
@@ -45,8 +45,8 @@ module Minfraud
45
45
  super(record)
46
46
 
47
47
  @confidence = get('confidence')
48
- @id = get('id')
49
- @last_seen = get('last_seen')
48
+ @id = get('id')
49
+ @last_seen = get('last_seen')
50
50
  @local_time = get('local_time')
51
51
  end
52
52
  end
@@ -43,11 +43,11 @@ module Minfraud
43
43
  def initialize(record)
44
44
  super(record)
45
45
 
46
- @domain = Minfraud::Model::EmailDomain.new(get('domain'))
47
- @first_seen = get('first_seen')
46
+ @domain = Minfraud::Model::EmailDomain.new(get('domain'))
47
+ @first_seen = get('first_seen')
48
48
  @is_disposable = get('is_disposable')
49
- @is_free = get('is_free')
50
- @is_high_risk = get('is_high_risk')
49
+ @is_free = get('is_free')
50
+ @is_high_risk = get('is_high_risk')
51
51
  end
52
52
  end
53
53
  end
@@ -20,7 +20,7 @@ module Minfraud
20
20
  def initialize(record)
21
21
  super(record)
22
22
 
23
- @code = get('code')
23
+ @code = get('code')
24
24
  @error = get('error')
25
25
  end
26
26
  end
@@ -52,13 +52,13 @@ module Minfraud
52
52
  def initialize(record, locales)
53
53
  super(record, locales)
54
54
 
55
- @billing_address = Minfraud::Model::BillingAddress.new(
55
+ @billing_address = Minfraud::Model::BillingAddress.new(
56
56
  get('billing_address')
57
57
  )
58
- @credit_card = Minfraud::Model::CreditCard.new(get('credit_card'))
59
- @device = Minfraud::Model::Device.new(get('device'))
60
- @email = Minfraud::Model::Email.new(get('email'))
61
- @ip_address = Minfraud::Model::IPAddress.new(get('ip_address'), locales)
58
+ @credit_card = Minfraud::Model::CreditCard.new(get('credit_card'))
59
+ @device = Minfraud::Model::Device.new(get('device'))
60
+ @email = Minfraud::Model::Email.new(get('email'))
61
+ @ip_address = Minfraud::Model::IPAddress.new(get('ip_address'), locales)
62
62
  @shipping_address = Minfraud::Model::ShippingAddress.new(
63
63
  get('shipping_address')
64
64
  )
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'maxmind/geoip2/model/insights'
4
4
  require 'minfraud/model/geoip2_location'
5
+ require 'minfraud/model/ip_risk_reason'
5
6
 
6
7
  module Minfraud
7
8
  module Model
@@ -13,9 +14,20 @@ module Minfraud
13
14
  # @return [Float]
14
15
  attr_reader :risk
15
16
 
17
+ # This field contains IPRiskReason objects identifying the reasons why
18
+ # the IP address received the associated risk. This will be an empty
19
+ # array if there are no reasons.
20
+ #
21
+ # @return [Array<Minfraud::Model::IPRiskReason>]
22
+ attr_reader :risk_reasons
23
+
16
24
  # @!visibility private
17
25
  def initialize(record, locales)
18
- super(record, locales)
26
+ if record
27
+ super(record, locales)
28
+ else
29
+ super({}, locales)
30
+ end
19
31
 
20
32
  if record
21
33
  @location = Minfraud::Model::GeoIP2Location.new(record.fetch('location', nil))
@@ -28,6 +40,13 @@ module Minfraud
28
40
  @risk = nil
29
41
  end
30
42
 
43
+ @risk_reasons = []
44
+ if record && record.key?('risk_reasons')
45
+ record['risk_reasons'].each do |r|
46
+ @risk_reasons << Minfraud::Model::IPRiskReason.new(r)
47
+ end
48
+ end
49
+
31
50
  # Decorate objects with deprecated attributes and names for backwards
32
51
  # compatibility. Do this here rather than with the overhead of
33
52
  # subclasses/modules for them in the hope that one day we can delete
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minfraud/model/abstract'
4
+
5
+ module Minfraud
6
+ module Model
7
+ # Reason for the IP risk.
8
+ #
9
+ # This class provides both a machine-readable code and a human-readable
10
+ # explanation of the reason for the IP risk score.
11
+ #
12
+ # Although more codes may be added in the future, the current codes are:
13
+ #
14
+ # * ANONYMOUS_IP - The IP address belongs to an anonymous network. See the
15
+ # object at ip_address.traits for more details.
16
+ # * BILLING_POSTAL_VELOCITY - Many different billing postal codes have been
17
+ # seen on this IP address.
18
+ # * EMAIL_VELOCITY - Many different email addresses have been seen on this
19
+ # IP address.
20
+ # * HIGH_RISK_DEVICE - A high risk device was seen on this IP address.
21
+ # * HIGH_RISK_EMAIL - A high risk email address was seen on this IP address
22
+ # in your past transactions.
23
+ # * ISSUER_ID_NUMBER_VELOCITY - Many different issuer ID numbers have been
24
+ # seen on this IP address.
25
+ # * MINFRAUD_NETWORK_ACTIVITY - Suspicious activity has been seen on this
26
+ # IP address across minFraud customers.
27
+ class IPRiskReason < Abstract
28
+ # This value is a machine-readable code identifying the reason.
29
+ #
30
+ # @return [String, nil]
31
+ attr_reader :code
32
+
33
+ # This field provides a human-readable explanation of the reason. The
34
+ # text may change at any time and should not be matched against.
35
+ #
36
+ # @return [String, nil]
37
+ attr_reader :reason
38
+
39
+ # @!visibility private
40
+ def initialize(record)
41
+ super(record)
42
+
43
+ @code = get('code')
44
+ @reason = get('reason')
45
+ end
46
+ end
47
+ end
48
+ end
@@ -39,9 +39,9 @@ module Minfraud
39
39
  def initialize(record)
40
40
  super(record)
41
41
 
42
- @name = get('name')
43
- @phone_number = get('phone_number')
44
- @matches_provided_name = get('matches_provided_name')
42
+ @name = get('name')
43
+ @phone_number = get('phone_number')
44
+ @matches_provided_name = get('matches_provided_name')
45
45
  @matches_provided_phone_number = get('matches_provided_phone_number')
46
46
  end
47
47
  end
@@ -58,13 +58,13 @@ module Minfraud
58
58
  def initialize(record, _locales)
59
59
  super(record)
60
60
 
61
- @disposition = Minfraud::Model::Disposition.new(get('disposition'))
62
- @funds_remaining = get('funds_remaining')
63
- @id = get('id')
64
- @ip_address = Minfraud::Model::ScoreIPAddress.new(get('ip_address'))
61
+ @disposition = Minfraud::Model::Disposition.new(get('disposition'))
62
+ @funds_remaining = get('funds_remaining')
63
+ @id = get('id')
64
+ @ip_address = Minfraud::Model::ScoreIPAddress.new(get('ip_address'))
65
65
  @queries_remaining = get('queries_remaining')
66
- @risk_score = get('risk_score')
67
- @warnings = []
66
+ @risk_score = get('risk_score')
67
+ @warnings = []
68
68
  if record && record.key?('warnings')
69
69
  record['warnings'].each do |w|
70
70
  @warnings << Minfraud::Model::Warning.new(w)
@@ -23,7 +23,7 @@ module Minfraud
23
23
  super(record)
24
24
 
25
25
  @distance_to_billing_address = get('distance_to_billing_address')
26
- @is_high_risk = get('is_high_risk')
26
+ @is_high_risk = get('is_high_risk')
27
27
  end
28
28
  end
29
29
  end
@@ -59,6 +59,12 @@ module Minfraud
59
59
  # @return [Float, nil]
60
60
  attr_reader :cvv_result
61
61
 
62
+ # The risk associated with the device. If present, this is a value in the
63
+ # range of 0.01 to 99.
64
+ #
65
+ # @return [Float, nil]
66
+ attr_reader :device
67
+
62
68
  # The risk associated with the particular email address. If present, this
63
69
  # is a value in the range 0.01 to 99.
64
70
  #
@@ -71,6 +77,13 @@ module Minfraud
71
77
  # @return [Float, nil]
72
78
  attr_reader :email_domain
73
79
 
80
+ # The risk associated with the email address local part (the part of
81
+ # the email address before the @ symbol). If present, this is a value
82
+ # in the range 0.01 to 99.
83
+ #
84
+ # @return [Float, nil]
85
+ attr_reader :email_local_part
86
+
74
87
  # The risk associated with the issuer ID number on the email domain. If
75
88
  # present, this is a value in the range 0.01 to 99.
76
89
  #
@@ -111,6 +124,12 @@ module Minfraud
111
124
  # @return [Float, nil]
112
125
  attr_reader :phone_number
113
126
 
127
+ # The risk associated with the shipping address. If present, this is a
128
+ # value in the range 0.01 to 99.
129
+ #
130
+ # @return [Float, nil]
131
+ attr_reader :shipping_address
132
+
114
133
  # The risk associated with the distance between the shipping address and
115
134
  # the IP location for the given IP address. If present, this is a value
116
135
  # in the range 0.01 to 99.
@@ -129,27 +148,30 @@ module Minfraud
129
148
  def initialize(record)
130
149
  super(record)
131
150
 
132
- @avs_result = get('avs_result')
133
- @billing_address = get('billing_address')
134
- @billing_address_distance_to_ip_location = get(
151
+ @avs_result = get('avs_result')
152
+ @billing_address = get('billing_address')
153
+ @billing_address_distance_to_ip_location = get(
135
154
  'billing_address_distance_to_ip_location'
136
155
  )
137
- @browser = get('browser')
138
- @chargeback = get('chargeback')
139
- @country = get('country')
140
- @country_mismatch = get('country_mismatch')
141
- @cvv_result = get('cvv_result')
142
- @email_address = get('email_address')
143
- @email_domain = get('email_domain')
144
- @email_tenure = get('email_tenure')
145
- @ip_tenure = get('ip_tenure')
146
- @issuer_id_number = get('issuer_id_number')
147
- @order_amount = get('order_amount')
148
- @phone_number = get('phone_number')
156
+ @browser = get('browser')
157
+ @chargeback = get('chargeback')
158
+ @country = get('country')
159
+ @country_mismatch = get('country_mismatch')
160
+ @cvv_result = get('cvv_result')
161
+ @device = get('device')
162
+ @email_address = get('email_address')
163
+ @email_domain = get('email_domain')
164
+ @email_local_part = get('email_local_part')
165
+ @email_tenure = get('email_tenure')
166
+ @ip_tenure = get('ip_tenure')
167
+ @issuer_id_number = get('issuer_id_number')
168
+ @order_amount = get('order_amount')
169
+ @phone_number = get('phone_number')
170
+ @shipping_address = get('shipping_address')
149
171
  @shipping_address_distance_to_ip_location = get(
150
172
  'shipping_address_distance_to_ip_location'
151
173
  )
152
- @time_of_day = get('time_of_day')
174
+ @time_of_day = get('time_of_day')
153
175
  end
154
176
  end
155
177
  end
@@ -54,8 +54,8 @@ module Minfraud
54
54
  def initialize(record)
55
55
  super(record)
56
56
 
57
- @code = get('code')
58
- @warning = get('warning')
57
+ @code = get('code')
58
+ @warning = get('warning')
59
59
  @input_pointer = get('input_pointer')
60
60
  end
61
61
  end
@@ -1,36 +1,56 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Minfraud
4
+ # Report is used to perform minFraud Report Transaction API requests.
5
+ #
6
+ # @see https://dev.maxmind.com/minfraud/report-transaction/
2
7
  class Report
3
8
  include ::Minfraud::HTTPService
4
9
 
5
- # @!attribute transaction
6
- # @return [Minfraud::Components::Report::Transaction] Report::Transaction component
10
+ # The Report::Transaction component.
11
+ #
12
+ # @return [Minfraud::Components::Report::Transaction, nil]
7
13
  attr_accessor :transaction
8
14
 
9
- # @param [Hash] params hash of parameters
10
- # @return [Minfraud::ReportTransaction] ReportTransaction instance
15
+ # @param params [Hash] Hash of parameters. The only supported key is
16
+ # +:transaction+, which should have a
17
+ # +Minfraud::Components::Report::Transaction+ as its value.
11
18
  def initialize(params = {})
12
19
  @transaction = params[:transaction]
13
20
  end
14
21
 
15
- # @method report_transaction
16
- # Makes a request to the minFraud report transactions API.
17
- # Raises an error in case of invalid response.
22
+ # Perform a request to the minFraud Report Transaction API.
23
+ #
18
24
  # @return [nil]
25
+ #
26
+ # @raise [Minfraud::AuthorizationError] If there was an authentication
27
+ # problem.
28
+ #
29
+ # @raise [Minfraud::ClientError] If there was a critical problem with one
30
+ # of your inputs.
31
+ #
32
+ # @raise [Minfraud::ServerError] If the server reported an error of some
33
+ # kind.
19
34
  def report_transaction
20
- raw = request.perform(verb: :post, endpoint: 'transactions/report', body: @transaction.to_json)
35
+ raw = request.perform(
36
+ verb: :post,
37
+ endpoint: 'transactions/report',
38
+ body: @transaction.to_json,
39
+ )
21
40
 
22
41
  response = ::Minfraud::HTTPService::Response.new(
23
- status: raw.status.to_i,
24
- body: raw.body,
42
+ status: raw.status.to_i,
43
+ body: raw.body,
25
44
  headers: raw.headers
26
45
  )
46
+
27
47
  ::Minfraud::ErrorHandler.examine(response)
28
48
 
29
- return nil
49
+ nil
30
50
  end
31
51
 
32
- # Creates memoized Minfraud::HTTPService::Request instance
33
- # @return [Minfraud::HTTPService::Request] Request instance based on configuration params
52
+ private
53
+
34
54
  def request
35
55
  @request ||= Request.new(::Minfraud::HTTPService.configuration)
36
56
  end