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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aa255a8f579aa729b4ceeb84db99f283bafdc2276fc6eba3d52e6133a8e2d4ea
4
- data.tar.gz: 1d9717004f0f07eadf3d986f4f697f4d2c41ef7c08c21b9b1f3b7e6291c36286
3
+ metadata.gz: af8e0a313e978adbd8ccfdf6fccad4652ad0b5c4df5f7812da097f2be4d5390e
4
+ data.tar.gz: 8d766ee43c166bc26a8c8643cded1d7a43a27cf6cc531e9fddaf66028ab0ebde
5
5
  SHA512:
6
- metadata.gz: a57eac0733d6c1d64319c80f458f00585897030433414ab0b4888606fedafac833e5fd1298fe608f8a343b87536ad2974bc794bba9317a5043980aa689c2e0cd
7
- data.tar.gz: 0ef9a279e2ed6d9a08b3f972338f7ade34ecf1f2c409e6777333c9a6afcf1dbab3c03927b8e6a350c54ed4dd2c86bdd64672a36f51caa2087bfb8e53ab824b2a
6
+ metadata.gz: 497a1c19029b36879b1b2f1b42f7037cfa205b24b199d71c84564a1cf26136de41f6b7fc8fdb9c9ffa163d3f82b8283d159f017d887aaa9709dfd059f1333625
7
+ data.tar.gz: 72f3fd755450dd1f68b3f675fc181e3a326574bcde905ee7e1b3e64951c2c009788124b2e063e99ed6d080430d7f3d093bf64b8f8dfb78c452436de3937e5cbd
@@ -7,6 +7,6 @@ jobs:
7
7
  - uses: actions/checkout@v2
8
8
  - uses: ruby/setup-ruby@v1
9
9
  with:
10
- ruby-version: 2.7
10
+ ruby-version: '3.0'
11
11
  - run: bundle install
12
12
  - run: bundle exec rake -t rubocop
@@ -16,6 +16,7 @@ jobs:
16
16
  2.5,
17
17
  2.6,
18
18
  2.7,
19
+ '3.0',
19
20
  jruby,
20
21
  ]
21
22
  exclude:
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,4 +1,4 @@
1
1
  # How to release
2
2
 
3
3
  See
4
- [here](https://github.com/maxmind/MaxMind-DB-Reader-ruby/blob/master/README.dev.md).
4
+ [here](https://github.com/maxmind/MaxMind-DB-Reader-ruby/blob/main/README.dev.md).
@@ -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 = params[:address]
28
- @domain = params[: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
@@ -22,6 +22,8 @@ module Minfraud
22
22
  :altapay,
23
23
  :amazon_payments,
24
24
  :american_express_payment_gateway,
25
+ :apple_pay,
26
+ :aps_payments,
25
27
  :authorizenet,
26
28
  :balanced,
27
29
  :beanstream,
@@ -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 as Hash where each key is a symbol corresponding
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
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Minfraud
4
4
  # The Gem version.
5
- VERSION = '1.4.1'
5
+ VERSION = '1.5.0'
6
6
  end
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.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: 2020-12-01 00:00:00.000000000 Z
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