minfraud 1.1.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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