minfraud 1.4.1 → 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 +1 -1
- data/.github/workflows/test.yml +1 -0
- data/CHANGELOG.md +16 -0
- data/README.dev.md +1 -1
- data/lib/minfraud/components/email.rb +92 -3
- data/lib/minfraud/components/payment.rb +2 -0
- data/lib/minfraud/components/shopping_cart.rb +1 -1
- data/lib/minfraud/model/ip_address.rb +15 -0
- data/lib/minfraud/model/ip_risk_reason.rb +48 -0
- data/lib/minfraud/version.rb +1 -1
- data/minfraud.gemspec +1 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af8e0a313e978adbd8ccfdf6fccad4652ad0b5c4df5f7812da097f2be4d5390e
|
4
|
+
data.tar.gz: 8d766ee43c166bc26a8c8643cded1d7a43a27cf6cc531e9fddaf66028ab0ebde
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 497a1c19029b36879b1b2f1b42f7037cfa205b24b199d71c84564a1cf26136de41f6b7fc8fdb9c9ffa163d3f82b8283d159f017d887aaa9709dfd059f1333625
|
7
|
+
data.tar.gz: 72f3fd755450dd1f68b3f675fc181e3a326574bcde905ee7e1b3e64951c2c009788124b2e063e99ed6d080430d7f3d093bf64b8f8dfb78c452436de3937e5cbd
|
data/.github/workflows/test.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# Minfraud Changelog
|
2
2
|
|
3
|
+
## v1.5.0 (2021-02-02)
|
4
|
+
|
5
|
+
* Add the `hash_address` attribute to `Minfraud::Components::Email`. If
|
6
|
+
this is `true`, the MD5 hash of the `address` will be sent instead of the
|
7
|
+
plain text `address`. Use this if you prefer to send the hash of the
|
8
|
+
`address` rather than the plain text. Note that this normalizes the
|
9
|
+
`address`, so we recommend using it as opposed to hashing the `address`
|
10
|
+
manually.
|
11
|
+
* The email `domain` input is now automatically set if the email `address`
|
12
|
+
input is set but the `domain` is not.
|
13
|
+
* Adds new payment processors `:apple_pay` and `:aps_payments` to
|
14
|
+
`Minfraud::Components::Payment`.
|
15
|
+
* Added support for the IP address risk reasons in the minFraud Insights
|
16
|
+
and Factors responses. This is available at `.ip_address.risk_reasons`.
|
17
|
+
It is an array of `IPRiskReason` objects.
|
18
|
+
|
3
19
|
## v1.4.1 (2020-12-01)
|
4
20
|
|
5
21
|
* Do not throw an exception if the response does not include IP address
|
data/README.dev.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'digest/md5'
|
4
|
+
require 'simpleidn'
|
5
|
+
|
3
6
|
module Minfraud
|
4
7
|
module Components
|
5
8
|
# Email corresponds to the email object of a minFraud request.
|
@@ -11,7 +14,8 @@ module Minfraud
|
|
11
14
|
# This field must be either be a valid email address or an MD5 of the
|
12
15
|
# lowercased email used in the transaction. Important: if using the MD5
|
13
16
|
# hash, please be sure to convert the email address to lowercase before
|
14
|
-
# calculating its MD5 hash.
|
17
|
+
# calculating its MD5 hash. Instead of converting an address to an MD5
|
18
|
+
# hash yourself, please use the hash_address attribute in this class.
|
15
19
|
#
|
16
20
|
# @return [String, nil]
|
17
21
|
attr_accessor :address
|
@@ -21,15 +25,46 @@ module Minfraud
|
|
21
25
|
# @return [String, nil]
|
22
26
|
attr_accessor :domain
|
23
27
|
|
28
|
+
# By default, the address will be sent in plain text. If this is set
|
29
|
+
# true, the address will instead be sent as an MD5 hash.
|
30
|
+
#
|
31
|
+
# @return [Boolean, nil]
|
32
|
+
attr_accessor :hash_address
|
33
|
+
|
24
34
|
# @param params [Hash] Hash of parameters. Each key/value should
|
25
35
|
# correspond to one of the available attributes.
|
26
36
|
def initialize(params = {})
|
27
|
-
@address
|
28
|
-
@domain
|
37
|
+
@address = params[:address]
|
38
|
+
@domain = params[:domain]
|
39
|
+
@hash_address = params[:hash_address]
|
29
40
|
|
30
41
|
validate
|
31
42
|
end
|
32
43
|
|
44
|
+
# A JSON representation of Minfraud::Components::Email.
|
45
|
+
#
|
46
|
+
# @return [Hash]
|
47
|
+
def to_json(*_args)
|
48
|
+
json = super
|
49
|
+
|
50
|
+
if json['address'] && !json['domain']
|
51
|
+
_, domain = address.split('@', 2)
|
52
|
+
if domain
|
53
|
+
domain = clean_domain(domain)
|
54
|
+
json['domain'] = domain if domain
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
if json.delete('hash_address') && json['address']
|
59
|
+
hash = hash_email_address(json['address'])
|
60
|
+
|
61
|
+
# We could consider clearing the key if !hash.
|
62
|
+
json['address'] = hash if hash
|
63
|
+
end
|
64
|
+
|
65
|
+
json
|
66
|
+
end
|
67
|
+
|
33
68
|
private
|
34
69
|
|
35
70
|
def validate
|
@@ -38,6 +73,60 @@ module Minfraud
|
|
38
73
|
validate_email('email', @address)
|
39
74
|
validate_string('domain', 255, @domain)
|
40
75
|
end
|
76
|
+
|
77
|
+
def hash_email_address(address)
|
78
|
+
address = clean_email_address(address)
|
79
|
+
return nil if !address
|
80
|
+
|
81
|
+
Digest::MD5.hexdigest(address)
|
82
|
+
end
|
83
|
+
|
84
|
+
def clean_email_address(address)
|
85
|
+
address = address.strip
|
86
|
+
address.downcase!
|
87
|
+
|
88
|
+
local_part, domain = address.split('@', 2)
|
89
|
+
return nil if !local_part || !domain
|
90
|
+
|
91
|
+
domain = clean_domain(domain)
|
92
|
+
|
93
|
+
if domain == 'yahoo.com'
|
94
|
+
local_part.sub!(/\A([^-]+)-.*\z/, '\1')
|
95
|
+
else
|
96
|
+
local_part.sub!(/\A([^+]+)\+.*\z/, '\1')
|
97
|
+
end
|
98
|
+
|
99
|
+
"#{local_part}@#{domain}"
|
100
|
+
end
|
101
|
+
|
102
|
+
TYPO_DOMAINS = {
|
103
|
+
# gmail.com
|
104
|
+
'35gmai.com' => 'gmail.com',
|
105
|
+
'636gmail.com' => 'gmail.com',
|
106
|
+
'gamil.com' => 'gmail.com',
|
107
|
+
'gmail.comu' => 'gmail.com',
|
108
|
+
'gmial.com' => 'gmail.com',
|
109
|
+
'gmil.com' => 'gmail.com',
|
110
|
+
'yahoogmail.com' => 'gmail.com',
|
111
|
+
# outlook.com
|
112
|
+
'putlook.com' => 'outlook.com',
|
113
|
+
}.freeze
|
114
|
+
private_constant :TYPO_DOMAINS
|
115
|
+
|
116
|
+
def clean_domain(domain)
|
117
|
+
domain = domain.strip
|
118
|
+
|
119
|
+
# We could use delete_suffix!, but that is in Ruby 2.5+ only.
|
120
|
+
domain.sub!(/\.\z/, '')
|
121
|
+
|
122
|
+
domain = SimpleIDN.to_ascii(domain)
|
123
|
+
|
124
|
+
if TYPO_DOMAINS.key?(domain)
|
125
|
+
domain = TYPO_DOMAINS[domain]
|
126
|
+
end
|
127
|
+
|
128
|
+
domain
|
129
|
+
end
|
41
130
|
end
|
42
131
|
end
|
43
132
|
end
|
@@ -13,7 +13,7 @@ module Minfraud
|
|
13
13
|
attr_accessor :items
|
14
14
|
|
15
15
|
# @param params [Array] Array of shopping cart items. You may provide
|
16
|
-
# each item as either
|
16
|
+
# each item as either a Hash where each key is a symbol corresponding
|
17
17
|
# to an item's field, or as a Minfraud:::Components::ShoppingCartItem
|
18
18
|
# object.
|
19
19
|
def initialize(params = [])
|
@@ -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,6 +14,13 @@ 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
|
@@ -32,6 +40,13 @@ module Minfraud
|
|
32
40
|
@risk = nil
|
33
41
|
end
|
34
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
|
+
|
35
50
|
# Decorate objects with deprecated attributes and names for backwards
|
36
51
|
# compatibility. Do this here rather than with the overhead of
|
37
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
|
data/lib/minfraud/version.rb
CHANGED
data/minfraud.gemspec
CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_runtime_dependency 'faraday', '>= 0.9.1', '< 2.0'
|
26
26
|
spec.add_runtime_dependency 'faraday_middleware', '>= 0.9.1', '< 2.0'
|
27
27
|
spec.add_runtime_dependency 'net-http-persistent', '>= 2.0.0', '< 5.0'
|
28
|
+
spec.add_runtime_dependency 'simpleidn', '>= 0.1.1'
|
28
29
|
|
29
30
|
spec.add_development_dependency 'bundler', '>= 1.16'
|
30
31
|
spec.add_development_dependency 'rake'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: minfraud
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kushnir.yb
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -70,6 +70,20 @@ dependencies:
|
|
70
70
|
- - "<"
|
71
71
|
- !ruby/object:Gem::Version
|
72
72
|
version: '5.0'
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: simpleidn
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: 0.1.1
|
80
|
+
type: :runtime
|
81
|
+
prerelease: false
|
82
|
+
version_requirements: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: 0.1.1
|
73
87
|
- !ruby/object:Gem::Dependency
|
74
88
|
name: bundler
|
75
89
|
requirement: !ruby/object:Gem::Requirement
|
@@ -211,6 +225,7 @@ files:
|
|
211
225
|
- lib/minfraud/model/geoip2_location.rb
|
212
226
|
- lib/minfraud/model/insights.rb
|
213
227
|
- lib/minfraud/model/ip_address.rb
|
228
|
+
- lib/minfraud/model/ip_risk_reason.rb
|
214
229
|
- lib/minfraud/model/issuer.rb
|
215
230
|
- lib/minfraud/model/score.rb
|
216
231
|
- lib/minfraud/model/score_ip_address.rb
|