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.
- checksums.yaml +4 -4
- data/.github/workflows/rubocop.yml +12 -0
- data/.github/workflows/test.yml +33 -0
- data/.rubocop.yml +108 -0
- data/CHANGELOG.md +57 -0
- data/Gemfile +4 -2
- data/README.dev.md +1 -1
- data/README.md +170 -55
- data/Rakefile +9 -3
- data/bin/console +4 -3
- data/lib/maxmind/geoip2/model/city.rb +3 -3
- data/lib/maxmind/geoip2/model/country.rb +5 -5
- data/lib/maxmind/geoip2/record/traits.rb +13 -4
- data/lib/minfraud.rb +44 -6
- data/lib/minfraud/assessments.rb +113 -53
- data/lib/minfraud/components/account.rb +31 -9
- data/lib/minfraud/components/addressable.rb +73 -26
- data/lib/minfraud/components/base.rb +26 -14
- data/lib/minfraud/components/billing.rb +5 -0
- data/lib/minfraud/components/credit_card.rb +64 -20
- data/lib/minfraud/components/custom_inputs.rb +14 -3
- data/lib/minfraud/components/device.rb +45 -15
- data/lib/minfraud/components/email.rb +120 -9
- data/lib/minfraud/components/event.rb +60 -24
- data/lib/minfraud/components/order.rb +59 -22
- data/lib/minfraud/components/payment.rb +44 -9
- data/lib/minfraud/components/report/transaction.rb +50 -39
- data/lib/minfraud/components/shipping.rb +14 -5
- data/lib/minfraud/components/shopping_cart.rb +19 -12
- data/lib/minfraud/components/shopping_cart_item.rb +42 -13
- data/lib/minfraud/enum.rb +22 -8
- data/lib/minfraud/error_handler.rb +32 -25
- data/lib/minfraud/errors.rb +22 -2
- data/lib/minfraud/http_service.rb +23 -8
- data/lib/minfraud/http_service/request.rb +19 -18
- data/lib/minfraud/http_service/response.rb +19 -14
- data/lib/minfraud/model/address.rb +4 -4
- data/lib/minfraud/model/credit_card.rb +7 -7
- data/lib/minfraud/model/device.rb +2 -2
- data/lib/minfraud/model/email.rb +4 -4
- data/lib/minfraud/model/error.rb +1 -1
- data/lib/minfraud/model/insights.rb +5 -5
- data/lib/minfraud/model/ip_address.rb +20 -1
- data/lib/minfraud/model/ip_risk_reason.rb +48 -0
- data/lib/minfraud/model/issuer.rb +3 -3
- data/lib/minfraud/model/score.rb +6 -6
- data/lib/minfraud/model/shipping_address.rb +1 -1
- data/lib/minfraud/model/subscores.rb +38 -16
- data/lib/minfraud/model/warning.rb +2 -2
- data/lib/minfraud/report.rb +33 -13
- data/lib/minfraud/resolver.rb +25 -17
- data/lib/minfraud/validates.rb +187 -0
- data/lib/minfraud/version.rb +4 -1
- data/minfraud.gemspec +8 -2
- metadata +77 -10
- 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
|
-
#
|
11
|
-
#
|
12
|
+
# HTTP response status.
|
13
|
+
#
|
14
|
+
# @return [Integer, nil]
|
12
15
|
attr_reader :status
|
13
16
|
|
14
|
-
#
|
17
|
+
# HTTP response model.
|
18
|
+
#
|
15
19
|
# @return [Minfraud::Model::Score, Minfraud::Model::Insights,
|
16
|
-
# Minfraud::Model::Factors]
|
20
|
+
# Minfraud::Model::Factors, nil]
|
17
21
|
attr_reader :body
|
18
22
|
|
19
|
-
#
|
20
|
-
#
|
23
|
+
# HTTP response headers.
|
24
|
+
#
|
25
|
+
# @return [Hash, nil]
|
21
26
|
attr_reader :headers
|
22
27
|
|
23
|
-
#
|
24
|
-
#
|
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
|
-
#
|
37
|
-
#
|
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:
|
63
|
+
factors: Minfraud::Model::Factors,
|
59
64
|
insights: Minfraud::Model::Insights,
|
60
|
-
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
|
46
|
-
@is_postal_in_city
|
47
|
-
@latitude
|
48
|
-
@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
|
63
|
-
@country
|
64
|
-
@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
|
69
|
-
@is_virtual
|
70
|
-
@issuer
|
71
|
-
@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
|
data/lib/minfraud/model/email.rb
CHANGED
@@ -43,11 +43,11 @@ module Minfraud
|
|
43
43
|
def initialize(record)
|
44
44
|
super(record)
|
45
45
|
|
46
|
-
@domain
|
47
|
-
@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
|
50
|
-
@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
|
data/lib/minfraud/model/error.rb
CHANGED
@@ -52,13 +52,13 @@ module Minfraud
|
|
52
52
|
def initialize(record, locales)
|
53
53
|
super(record, locales)
|
54
54
|
|
55
|
-
@billing_address
|
55
|
+
@billing_address = Minfraud::Model::BillingAddress.new(
|
56
56
|
get('billing_address')
|
57
57
|
)
|
58
|
-
@credit_card
|
59
|
-
@device
|
60
|
-
@email
|
61
|
-
@ip_address
|
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
|
-
|
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
|
43
|
-
@phone_number
|
44
|
-
@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
|
data/lib/minfraud/model/score.rb
CHANGED
@@ -58,13 +58,13 @@ module Minfraud
|
|
58
58
|
def initialize(record, _locales)
|
59
59
|
super(record)
|
60
60
|
|
61
|
-
@disposition
|
62
|
-
@funds_remaining
|
63
|
-
@id
|
64
|
-
@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
|
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)
|
@@ -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
|
133
|
-
@billing_address
|
134
|
-
@billing_address_distance_to_ip_location
|
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
|
138
|
-
@chargeback
|
139
|
-
@country
|
140
|
-
@country_mismatch
|
141
|
-
@cvv_result
|
142
|
-
@
|
143
|
-
@
|
144
|
-
@
|
145
|
-
@
|
146
|
-
@
|
147
|
-
@
|
148
|
-
@
|
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
|
174
|
+
@time_of_day = get('time_of_day')
|
153
175
|
end
|
154
176
|
end
|
155
177
|
end
|
data/lib/minfraud/report.rb
CHANGED
@@ -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
|
-
#
|
6
|
-
#
|
10
|
+
# The Report::Transaction component.
|
11
|
+
#
|
12
|
+
# @return [Minfraud::Components::Report::Transaction, nil]
|
7
13
|
attr_accessor :transaction
|
8
14
|
|
9
|
-
# @param
|
10
|
-
#
|
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
|
-
#
|
16
|
-
#
|
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(
|
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:
|
24
|
-
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
|
-
|
49
|
+
nil
|
30
50
|
end
|
31
51
|
|
32
|
-
|
33
|
-
|
52
|
+
private
|
53
|
+
|
34
54
|
def request
|
35
55
|
@request ||= Request.new(::Minfraud::HTTPService.configuration)
|
36
56
|
end
|