minfraud 1.4.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +7 -0
  3. data/.github/workflows/rubocop.yml +1 -1
  4. data/.github/workflows/test.yml +2 -4
  5. data/.rubocop.yml +4 -25
  6. data/CHANGELOG.md +97 -2
  7. data/Gemfile +0 -9
  8. data/LICENSE.txt +1 -1
  9. data/README.dev.md +1 -1
  10. data/README.md +13 -12
  11. data/lib/minfraud/assessments.rb +21 -16
  12. data/lib/minfraud/components/account.rb +1 -1
  13. data/lib/minfraud/components/billing.rb +1 -1
  14. data/lib/minfraud/components/credit_card.rb +47 -15
  15. data/lib/minfraud/components/custom_inputs.rb +1 -1
  16. data/lib/minfraud/components/device.rb +1 -1
  17. data/lib/minfraud/components/email.rb +93 -4
  18. data/lib/minfraud/components/event.rb +11 -11
  19. data/lib/minfraud/components/order.rb +1 -1
  20. data/lib/minfraud/components/payment.rb +153 -133
  21. data/lib/minfraud/components/report/transaction.rb +2 -2
  22. data/lib/minfraud/components/shipping.rb +2 -2
  23. data/lib/minfraud/components/shopping_cart.rb +2 -2
  24. data/lib/minfraud/components/shopping_cart_item.rb +3 -3
  25. data/lib/minfraud/http_service/response.rb +28 -21
  26. data/lib/minfraud/model/device.rb +1 -1
  27. data/lib/minfraud/model/disposition.rb +13 -6
  28. data/lib/minfraud/model/factors.rb +1 -1
  29. data/lib/minfraud/model/ip_address.rb +15 -43
  30. data/lib/minfraud/model/ip_risk_reason.rb +48 -0
  31. data/lib/minfraud/model/score.rb +1 -1
  32. data/lib/minfraud/model/subscores.rb +1 -23
  33. data/lib/minfraud/report.rb +19 -11
  34. data/lib/minfraud/validates.rb +2 -2
  35. data/lib/minfraud/version.rb +1 -1
  36. data/lib/minfraud.rb +18 -24
  37. data/minfraud.gemspec +14 -10
  38. metadata +58 -63
  39. data/lib/maxmind/geoip2/model/city.rb +0 -99
  40. data/lib/maxmind/geoip2/model/country.rb +0 -94
  41. data/lib/maxmind/geoip2/model/insights.rb +0 -38
  42. data/lib/maxmind/geoip2/record/abstract.rb +0 -46
  43. data/lib/maxmind/geoip2/record/city.rb +0 -62
  44. data/lib/maxmind/geoip2/record/continent.rb +0 -61
  45. data/lib/maxmind/geoip2/record/country.rb +0 -78
  46. data/lib/maxmind/geoip2/record/location.rb +0 -97
  47. data/lib/maxmind/geoip2/record/maxmind.rb +0 -41
  48. data/lib/maxmind/geoip2/record/place.rb +0 -52
  49. data/lib/maxmind/geoip2/record/postal.rb +0 -54
  50. data/lib/maxmind/geoip2/record/represented_country.rb +0 -47
  51. data/lib/maxmind/geoip2/record/subdivision.rb +0 -72
  52. data/lib/maxmind/geoip2/record/traits.rb +0 -233
  53. data/lib/minfraud/http_service/request.rb +0 -38
  54. data/lib/minfraud/http_service.rb +0 -45
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aa255a8f579aa729b4ceeb84db99f283bafdc2276fc6eba3d52e6133a8e2d4ea
4
- data.tar.gz: 1d9717004f0f07eadf3d986f4f697f4d2c41ef7c08c21b9b1f3b7e6291c36286
3
+ metadata.gz: e2805f5d3d40b2d325926a4a5614b86248bba07f905ffb37ec7dfa9589e97103
4
+ data.tar.gz: 6d70e15b76a295c376232e6bf277e619ed783c23e46460e89e527458813b44ec
5
5
  SHA512:
6
- metadata.gz: a57eac0733d6c1d64319c80f458f00585897030433414ab0b4888606fedafac833e5fd1298fe608f8a343b87536ad2974bc794bba9317a5043980aa689c2e0cd
7
- data.tar.gz: 0ef9a279e2ed6d9a08b3f972338f7ade34ecf1f2c409e6777333c9a6afcf1dbab3c03927b8e6a350c54ed4dd2c86bdd64672a36f51caa2087bfb8e53ab824b2a
6
+ metadata.gz: 7a4e77f3d92e6173426e5151b234badc9fbe2503e41178d104eeda51c016835c6459308eaaa810063666030369e89828f1919731add25be6b51e0bf50821704a
7
+ data.tar.gz: a07520d278d5191c2ac5dc9684d9d52ca670a494b088b56b4f8b920a0198ad53469e473d8114e9d33a891e4daa3f5ffa3573cf2190284dfb993b7e57742f9ca3
@@ -0,0 +1,7 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ open-pull-requests-limit: 10
@@ -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.1
11
11
  - run: bundle install
12
12
  - run: bundle exec rake -t rubocop
@@ -9,13 +9,11 @@ jobs:
9
9
  os: [ubuntu-latest, windows-latest, macos-latest]
10
10
  version:
11
11
  [
12
- 2.1,
13
- 2.2,
14
- 2.3,
15
- 2.4,
16
12
  2.5,
17
13
  2.6,
18
14
  2.7,
15
+ '3.0',
16
+ 3.1,
19
17
  jruby,
20
18
  ]
21
19
  exclude:
data/.rubocop.yml CHANGED
@@ -1,5 +1,6 @@
1
- Gemspec/RequiredRubyVersion:
2
- Enabled: false # We support 2.1+, but rubocop supports 2.4+.
1
+ AllCops:
2
+ TargetRubyVersion: 2.5
3
+ NewCops: enable
3
4
 
4
5
  # Metrics.
5
6
 
@@ -39,7 +40,7 @@ Layout/IndentationStyle:
39
40
  # Style.
40
41
 
41
42
  Style/HashSyntax:
42
- EnforcedStyle: ruby19_no_mixed_keys # Default is ruby19.
43
+ EnforcedStyle: ruby19_no_mixed_keys # Default is ruby19. This one is better.
43
44
 
44
45
  Style/CollectionMethods:
45
46
  Enabled: true # Default is false.
@@ -53,9 +54,6 @@ Style/NegatedIf: # I disagree with this.
53
54
  Style/IfUnlessModifier: # This doesn't always make sense.
54
55
  Enabled: false
55
56
 
56
- Style/SymbolArray:
57
- EnforcedStyle: brackets # Default is percent, but 1.9 doesn't support that.
58
-
59
57
  # Trailing commas are often good.
60
58
  Style/TrailingCommaInArguments:
61
59
  Enabled: false
@@ -64,9 +62,6 @@ Style/TrailingCommaInArrayLiteral:
64
62
  Style/TrailingCommaInHashLiteral:
65
63
  Enabled: false
66
64
 
67
- Style/SafeNavigation:
68
- Enabled: false # Default is true, but this 1.9 doesn't support it.
69
-
70
65
  # Default is both which is probably fine, but it changes code and I don't want
71
66
  # to investigate any possible behavior change right now.
72
67
  Style/EmptyElse:
@@ -75,25 +70,12 @@ Style/EmptyElse:
75
70
  Style/ConditionalAssignment:
76
71
  Enabled: false # This produces kind of strange results.
77
72
 
78
- Style/Dir:
79
- Enabled: false # This is good, but not supported on 1.9.
80
-
81
- Style/ExpandPathArguments:
82
- Enabled: false # This causes us to use __dir__ which 1.9 doesn't support.
83
-
84
73
  Style/GuardClause:
85
74
  Enabled: false # Doesn't always make sense.
86
75
 
87
- Style/Documentation:
88
- Enabled: false # We should enable this, but allow for pre-existing code.
89
-
90
76
  Style/FormatStringToken:
91
77
  Enabled: false # Seems unnecessary.
92
78
 
93
- # Asks to use x.negative? instead of x < 0. But this isn't available until 2.3.
94
- Style/NumericPredicate:
95
- Enabled: false
96
-
97
79
  # Seems unnecessary. Asks us to call super in a bunch of places when there's no
98
80
  # need.
99
81
  Lint/MissingSuper:
@@ -103,6 +85,3 @@ Lint/MissingSuper:
103
85
 
104
86
  Naming/VariableNumber:
105
87
  Enabled: false # Doesn't always make sense.
106
-
107
- AllCops:
108
- NewCops: enable
data/CHANGELOG.md CHANGED
@@ -1,4 +1,98 @@
1
- # Minfraud Changelog
1
+ # Changelog
2
+
3
+ ## v2.1.0 (2022-01-25)
4
+
5
+ * Adds the following new processor to `Minfraud::Components::Payment`:
6
+ * `:windcave`
7
+ * The `last_4_digits` input to `Minfraud::Components::CreditCard` has been
8
+ deprecated in favor of `last_digits` and will be removed in a future
9
+ release. `last_digits`/`last_4_digits` also now supports two digit values
10
+ in addition to the previous four digit values.
11
+ * Eight digit `issuer_id_number` inputs are now supported by
12
+ `Minfraud::Components::CreditCard` in addition to the previously accepted
13
+ six digit `issuer_id_number`. In most cases, you should send the last four
14
+ digits for `last_digits`. If you send an `issuer_id_number` that contains
15
+ an eight digit IIN, and if the credit card brand is not one of the
16
+ following, you should send the last two digits for `last_digits`:
17
+ * `Discover`
18
+ * `JCB`
19
+ * `Mastercard`
20
+ * `UnionPay`
21
+ * `Visa`
22
+
23
+ ## v2.0.0 (2021-12-06)
24
+
25
+ * Breaking change from 1.x: Removed deprecated methods
26
+ `is_in_european_union`, `is_anonymous`, `is_anonymous_vpn`,
27
+ `is_hosting_provider`, `is_public_proxy`, and `is_tor_exit_node`. The
28
+ non-deprecated equivalents are `in_european_union?`, `anonymous?`,
29
+ `anonymous_vpn?`, `hosting_provider?`, `public_proxy?`, and
30
+ `tor_exit_node?`.
31
+ * Breaking change from 1.x: Removed deprecated methods for deprecated
32
+ subscores: `email_tenure` and `ip_tenure`. For `email_tenure`, please use
33
+ the `email_address` subscore instead. For `ip_tenure`, please use
34
+ `risk_score` instead.
35
+ * Breaking change from 1.x: Removed deprecated method for deprecated
36
+ attribute `ip_address.country.is_high_risk`.
37
+ * Breaking change from 1.x: Switches HTTP client from faraday to http.rb.
38
+ There should be no behavior change for most users, but this is
39
+ technically a breaking change from the perspective of semver. Most users
40
+ should not be affected as the changes are limited to attributes and
41
+ classes that would not normally be accessed outside the gem.
42
+ * Breaking change from 1.x: `user_id` is no longer supported as a way to
43
+ configure your MaxMind account ID. Use `account_id` instead.
44
+ * Breaking change from 1.x: Removed the `Minfraud.configuration` method.
45
+ * Breaking change from 1.x: Localized names are no longer exposed via
46
+ methods on `names` objects, only as hash keys. For example, use
47
+ `response.ip_address.country.names['en']` instead of
48
+ `response.ip_address.country.names.en`. The latter was deprecated.
49
+ * Adds mobile country code (MCC) and mobile network code (MNC) to minFraud
50
+ Insights and Factors responses. These are available at
51
+ `response.ip_address.traits.mobile_country_code` and
52
+ `response.ip_address.traits.mobile_network_code`. We expect this data to
53
+ be available by late January, 2022.
54
+ * Adds the following new processors to `Minfraud::Components::Payment`:
55
+ * `:boacompra`
56
+ * `:boku`
57
+ * `:coregateway`
58
+ * `:fiserv`
59
+ * `:neopay`
60
+ * `:neosurf`
61
+ * `:openbucks`
62
+ * `:paysera`
63
+ * `:payvision`
64
+ * `:trustly`
65
+ * Depend on the `maxmind-geoip2` gem. This allows us to delete classes from
66
+ that gem that we previously had included in this gem. There is no
67
+ functional difference.
68
+
69
+ ## v1.6.0 (2021-08-19)
70
+
71
+ * Adds new processor to `Minfraud::Components::Payment`: `:cardknox`,
72
+ `:creditguard`, `:credorax`, `:datacap`, `:dlocal`, `:onpay`, and
73
+ `:safecharge`.
74
+ * Adds `rule_label` to minFraud output `/disposition`.
75
+ * Adds support for the `/credit_card/was_3d_secure_successful` input. This is
76
+ available by setting the `was_3d_secure_successful` attribute on
77
+ `Minfraud::Components::CreditCard`.
78
+ * Ruby 2.5+ is now required. If you're using Ruby 2.1, 2.2, 2.3, or 2.4,
79
+ please use version 1.5.0 of this gem.
80
+
81
+ ## v1.5.0 (2021-02-02)
82
+
83
+ * Adds the `hash_address` attribute to `Minfraud::Components::Email`. If
84
+ this is `true`, the MD5 hash of the `address` will be sent instead of the
85
+ plain text `address`. Use this if you prefer to send the hash of the
86
+ `address` rather than the plain text. Note that this normalizes the
87
+ `address`, so we recommend using it as opposed to hashing the `address`
88
+ manually.
89
+ * The email `domain` input is now automatically set if the email `address`
90
+ input is set but the `domain` is not.
91
+ * Adds new payment processors `:apple_pay` and `:aps_payments` to
92
+ `Minfraud::Components::Payment`.
93
+ * Adds support for the IP address risk reasons in the minFraud Insights
94
+ and Factors responses. This is available at `.ip_address.risk_reasons`.
95
+ It is an array of `IPRiskReason` objects.
2
96
 
3
97
  ## v1.4.1 (2020-12-01)
4
98
 
@@ -10,7 +104,7 @@
10
104
 
11
105
  * IMPORTANT: Ruby 2.0 is no longer supported. If you're using Ruby 2.0,
12
106
  please use version 1.3.0.
13
- * Add handling for the `REQUEST_INVALID` error code.
107
+ * Adds handling for the `REQUEST_INVALID` error code.
14
108
  * The IP address is no longer a required input.
15
109
  * Adds new payment processor `:tsys` to `Minfraud::Components::Payment`.
16
110
 
@@ -75,6 +169,7 @@
75
169
  * Adds `amount` attribute to the `Minfraud::Components::Order` instances
76
170
 
77
171
  ## v1.0.3 (2016-11-24)
172
+
78
173
  * Adds `token` attribute to the `Minfraud::Components::CreditCard` instances
79
174
  according to the MinFraud Release Notes introduced on November 17, 2016
80
175
 
data/Gemfile CHANGED
@@ -2,13 +2,4 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- # coveralls fails on Ruby 1.9. My understanding is we don't need to run this on
6
- # more than one version anyway, so restrict to the current latest.
7
- version_pieces = RUBY_VERSION.split('.')
8
- major_version = version_pieces[0]
9
- minor_version = version_pieces[1]
10
- if major_version == '2' && minor_version == '7'
11
- gem 'coveralls', require: false
12
- end
13
-
14
5
  gemspec
data/LICENSE.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  The MIT License (MIT)
2
2
 
3
3
  Copyright (c) 2016-2020 kushnir.yb
4
- Copyright (c) 2020 MaxMind, Inc.
4
+ Copyright (c) 2020-2022 MaxMind, Inc.
5
5
 
6
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
7
  of this software and associated documentation files (the "Software"), to deal
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).
data/README.md CHANGED
@@ -3,9 +3,9 @@
3
3
  ## Description
4
4
 
5
5
  This package provides an API for the [MaxMind minFraud web
6
- services](https://dev.maxmind.com/minfraud/). This includes minFraud Score,
6
+ services](https://dev.maxmind.com/minfraud?lang=en). This includes minFraud Score,
7
7
  Insights, and Factors. It also includes our [minFraud Report Transaction
8
- API](https://dev.maxmind.com/minfraud/report-transaction/).
8
+ API](https://dev.maxmind.com/minfraud/report-a-transaction?lang=en).
9
9
 
10
10
  The legacy minFraud Standard and Premium services are not supported by this
11
11
  API.
@@ -122,14 +122,15 @@ assessment = Minfraud::Assessments.new(
122
122
  decline_code: 'invalid number',
123
123
  },
124
124
  credit_card: {
125
- issuer_id_number: '411111',
126
- last_4_digits: '7643',
127
- bank_name: 'Bank of No Hope',
128
- bank_phone_country_code: '1',
129
- bank_phone_number: '123-456-1234',
130
- token: 'abcd',
131
- avs_result: 'Y',
132
- cvv_result: 'N',
125
+ issuer_id_number: '411111',
126
+ last_digits: '7643',
127
+ bank_name: 'Bank of No Hope',
128
+ bank_phone_country_code: '1',
129
+ bank_phone_number: '123-456-1234',
130
+ token: 'abcd',
131
+ avs_result: 'Y',
132
+ cvv_result: 'N',
133
+ was_3d_secure_successful: true,
133
134
  },
134
135
  order: {
135
136
  amount: 323.21,
@@ -264,7 +265,7 @@ to the client API, please see
264
265
 
265
266
  ## Requirements
266
267
 
267
- This gem works with Ruby 2.1 and above.
268
+ This gem works with Ruby 2.5 and above.
268
269
 
269
270
  ## Contributing
270
271
 
@@ -282,7 +283,7 @@ This API uses [Semantic Versioning](https://semver.org/).
282
283
 
283
284
  Copyright (c) 2016-2020 kushnir.yb.
284
285
 
285
- Copyright (c) 2020 MaxMind, Inc.
286
+ Copyright (c) 2020-2022 MaxMind, Inc.
286
287
 
287
288
  The gem is available as open source under the terms of the [MIT
288
289
  License](https://opensource.org/licenses/MIT).
@@ -4,9 +4,8 @@ module Minfraud
4
4
  # Assessments is used to perform minFraud Score, Insights, and Factors
5
5
  # requests.
6
6
  #
7
- # @see https://dev.maxmind.com/minfraud/
7
+ # @see https://dev.maxmind.com/minfraud?lang=en
8
8
  class Assessments
9
- include ::Minfraud::HTTPService
10
9
  include ::Minfraud::Resolver
11
10
 
12
11
  # The Account component.
@@ -82,6 +81,8 @@ module Minfraud
82
81
  #
83
82
  # @return [Minfraud::HTTPService::Response]
84
83
  #
84
+ # @raise [JSON::ParserError] if there was invalid JSON in the response.
85
+ #
85
86
  # @raise [Minfraud::AuthorizationError] If there was an authentication
86
87
  # problem.
87
88
  #
@@ -98,6 +99,8 @@ module Minfraud
98
99
  #
99
100
  # @return [Minfraud::HTTPService::Response]
100
101
  #
102
+ # @raise [JSON::ParserError] if there was invalid JSON in the response.
103
+ #
101
104
  # @raise [Minfraud::AuthorizationError] If there was an authentication
102
105
  # problem.
103
106
  #
@@ -114,6 +117,8 @@ module Minfraud
114
117
  #
115
118
  # @return [Minfraud::HTTPService::Response]
116
119
  #
120
+ # @raise [JSON::ParserError] if there was invalid JSON in the response.
121
+ #
117
122
  # @raise [Minfraud::AuthorizationError] If there was an authentication
118
123
  # problem.
119
124
  #
@@ -129,18 +134,22 @@ module Minfraud
129
134
  private
130
135
 
131
136
  def perform_request(endpoint)
132
- raw = request.perform(
133
- verb: :post,
134
- endpoint: endpoint.to_s,
135
- body: request_body,
136
- )
137
+ response = nil
138
+ body = nil
139
+ Minfraud.connection_pool.with do |client|
140
+ response = client.post(
141
+ "/minfraud/v2.0/#{endpoint}",
142
+ json: request_body,
143
+ )
144
+
145
+ body = response.to_s
146
+ end
137
147
 
138
148
  response = ::Minfraud::HTTPService::Response.new(
139
- endpoint: endpoint,
140
- locales: @locales,
141
- status: raw.status.to_i,
142
- body: raw.body,
143
- headers: raw.headers
149
+ endpoint,
150
+ @locales,
151
+ response,
152
+ body,
144
153
  )
145
154
 
146
155
  ::Minfraud::ErrorHandler.examine(response)
@@ -153,9 +162,5 @@ module Minfraud
153
162
  mem.merge!(e.to_s => value.to_json)
154
163
  end
155
164
  end
156
-
157
- def request
158
- @request ||= Request.new(::Minfraud::HTTPService.configuration)
159
- end
160
165
  end
161
166
  end
@@ -4,7 +4,7 @@ module Minfraud
4
4
  module Components
5
5
  # Account corresponds to the account object of a minFraud request.
6
6
  #
7
- # @see https://dev.maxmind.com/minfraud/#Account_(/account)
7
+ # @see https://dev.maxmind.com/minfraud/api-documentation/requests?lang=en#schema--request--account
8
8
  class Account < Base
9
9
  include Minfraud::Validates
10
10
 
@@ -4,7 +4,7 @@ module Minfraud
4
4
  module Components
5
5
  # Billing corresponds to the billing object of a minFraud request.
6
6
  #
7
- # @see https://dev.maxmind.com/minfraud/#Billing_(/billing)
7
+ # @see https://dev.maxmind.com/minfraud/api-documentation/requests?lang=en#schema--request--billing
8
8
  class Billing < Addressable; end
9
9
  end
10
10
  end
@@ -4,20 +4,22 @@ module Minfraud
4
4
  module Components
5
5
  # CreditCard corresponds to the credit_card object of a minFraud request.
6
6
  #
7
- # @see https://dev.maxmind.com/minfraud/#Credit_Card_(/creditcard)
7
+ # @see https://dev.maxmind.com/minfraud/api-documentation/requests?lang=en#schema--request--credit-card
8
8
  class CreditCard < Base
9
9
  include Minfraud::Validates
10
10
 
11
- # The issuer ID number for the credit card. This is the first 6 digits of
12
- # the credit card number. It identifies the issuing bank.
11
+ # The issuer ID number for the credit card. This is the first 6 or 8
12
+ # digits of the credit card number. It identifies the issuing bank.
13
13
  #
14
14
  # @return [String, nil]
15
15
  attr_accessor :issuer_id_number
16
16
 
17
- # The last four digits of the credit card number.
17
+ # The last two or four digits of the credit card number.
18
+ #
19
+ # @see https://dev.maxmind.com/minfraud/api-documentation/requests?lang=en#schema--request--credit-card__last_digits
18
20
  #
19
21
  # @return [String, nil]
20
- attr_accessor :last_4_digits
22
+ attr_accessor :last_digits
21
23
 
22
24
  # The name of the issuing bank as provided by the end user.
23
25
  #
@@ -62,17 +64,46 @@ module Minfraud
62
64
  # @return [String, nil]
63
65
  attr_accessor :cvv_result
64
66
 
67
+ # Whether the outcome of 3-D Secure verification (e.g. Safekey,
68
+ # SecureCode, Verified by Visa) was successful. +true+ if customer
69
+ # verification was successful, or +false+ if the customer failed
70
+ # verification. If 3-D Secure verification was not used, was unavailable,
71
+ # or resulted in an outcome other than success or failure, do not
72
+ # include this field.
73
+ #
74
+ # @return [Boolean, nil]
75
+ attr_accessor :was_3d_secure_successful
76
+
77
+ # Get the last digits of the credit card number.
78
+ #
79
+ # @deprecated Use {::last_digits} instead.
80
+ #
81
+ # @return [String, nil]
82
+ def last_4_digits
83
+ @last_digits
84
+ end
85
+
86
+ # Set the last digits of the credit card number.
87
+ #
88
+ # @deprecated Use {::last_digits} instead.
89
+ #
90
+ # @return [String, nil]
91
+ def last_4_digits=(last4)
92
+ @last_digits = last4
93
+ end
94
+
65
95
  # @param params [Hash] Hash of parameters. Each key/value should
66
96
  # correspond to one of the available attributes.
67
97
  def initialize(params = {})
68
- @bank_phone_country_code = params[:bank_phone_country_code]
69
- @issuer_id_number = params[:issuer_id_number]
70
- @last_4_digits = params[:last_4_digits]
71
- @bank_name = params[:bank_name]
72
- @bank_phone_number = params[:bank_phone_number]
73
- @avs_result = params[:avs_result]
74
- @cvv_result = params[:cvv_result]
75
- @token = params[:token]
98
+ @bank_phone_country_code = params[:bank_phone_country_code]
99
+ @issuer_id_number = params[:issuer_id_number]
100
+ @last_digits = params[:last_digits] || params[:last_4_digits]
101
+ @bank_name = params[:bank_name]
102
+ @bank_phone_number = params[:bank_phone_number]
103
+ @avs_result = params[:avs_result]
104
+ @cvv_result = params[:cvv_result]
105
+ @token = params[:token]
106
+ @was_3d_secure_successful = params[:was_3d_secure_successful]
76
107
 
77
108
  validate
78
109
  end
@@ -83,13 +114,14 @@ module Minfraud
83
114
  return if !Minfraud.enable_validation
84
115
 
85
116
  validate_telephone_country_code('bank_phone_country_code', @bank_phone_country_code)
86
- validate_regex('issuer_id_number', /\A[0-9]{6}\z/, @issuer_id_number)
87
- validate_regex('last_4_digits', /\A[0-9]{4}\z/, @last_4_digits)
117
+ validate_regex('issuer_id_number', /\A(?:[0-9]{6}|[0-9]{8})\z/, @issuer_id_number)
118
+ validate_regex('last_digits', /\A(?:[0-9]{2}|[0-9]{4})\z/, @last_digits)
88
119
  validate_string('bank_name', 255, @bank_name)
89
120
  validate_string('bank_phone_number', 255, @bank_phone_number)
90
121
  validate_string('avs_result', 1, @avs_result)
91
122
  validate_string('cvv_result', 1, @cvv_result)
92
123
  validate_credit_card_token('token', @token)
124
+ validate_boolean('was_3d_secure_successful', @was_3d_secure_successful)
93
125
  end
94
126
  end
95
127
  end
@@ -5,7 +5,7 @@ module Minfraud
5
5
  # CustomInputs corresponds to the custom_inputs object of a minFraud
6
6
  # request.
7
7
  #
8
- # @see https://dev.maxmind.com/minfraud/#Custom_Inputs_(/custominputs)
8
+ # @see https://dev.maxmind.com/minfraud/api-documentation/requests?lang=en#schema--request--custom-inputs
9
9
  class CustomInputs < Base
10
10
  include Minfraud::Validates
11
11
 
@@ -4,7 +4,7 @@ module Minfraud
4
4
  module Components
5
5
  # Device corresponds to the device object of a minFraud request.
6
6
  #
7
- # @see https://dev.maxmind.com/minfraud/#Device_(/device)
7
+ # @see https://dev.maxmind.com/minfraud/api-documentation/requests?lang=en#schema--request--device
8
8
  class Device < Base
9
9
  include Minfraud::Validates
10
10
 
@@ -1,17 +1,21 @@
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.
6
9
  #
7
- # @see https://dev.maxmind.com/minfraud/#Email_(/email)
10
+ # @see https://dev.maxmind.com/minfraud/api-documentation/requests?lang=en#schema--request--email
8
11
  class Email < Base
9
12
  include Minfraud::Validates
10
13
 
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