minfraud 1.0.1 → 1.2.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.
Files changed (74) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/test.yml +46 -0
  3. data/.gitignore +2 -0
  4. data/.rubocop.yml +127 -0
  5. data/.travis.yml +20 -3
  6. data/CHANGELOG.md +56 -0
  7. data/CODE_OF_CONDUCT.md +4 -4
  8. data/Gemfile +11 -2
  9. data/LICENSE.txt +2 -1
  10. data/README.dev.md +4 -0
  11. data/README.md +107 -36
  12. data/Rakefile +18 -3
  13. data/bin/console +4 -3
  14. data/lib/maxmind/geoip2/model/city.rb +99 -0
  15. data/lib/maxmind/geoip2/model/country.rb +94 -0
  16. data/lib/maxmind/geoip2/model/insights.rb +38 -0
  17. data/lib/maxmind/geoip2/record/abstract.rb +46 -0
  18. data/lib/maxmind/geoip2/record/city.rb +62 -0
  19. data/lib/maxmind/geoip2/record/continent.rb +61 -0
  20. data/lib/maxmind/geoip2/record/country.rb +78 -0
  21. data/lib/maxmind/geoip2/record/location.rb +97 -0
  22. data/lib/maxmind/geoip2/record/maxmind.rb +41 -0
  23. data/lib/maxmind/geoip2/record/place.rb +52 -0
  24. data/lib/maxmind/geoip2/record/postal.rb +54 -0
  25. data/lib/maxmind/geoip2/record/represented_country.rb +47 -0
  26. data/lib/maxmind/geoip2/record/subdivision.rb +72 -0
  27. data/lib/maxmind/geoip2/record/traits.rb +224 -0
  28. data/lib/minfraud.rb +33 -8
  29. data/lib/minfraud/assessments.rb +25 -10
  30. data/lib/minfraud/components/account.rb +3 -1
  31. data/lib/minfraud/components/addressable.rb +11 -9
  32. data/lib/minfraud/components/base.rb +29 -5
  33. data/lib/minfraud/components/billing.rb +2 -0
  34. data/lib/minfraud/components/credit_card.rb +8 -1
  35. data/lib/minfraud/components/custom_inputs.rb +16 -0
  36. data/lib/minfraud/components/device.rb +13 -0
  37. data/lib/minfraud/components/email.rb +2 -0
  38. data/lib/minfraud/components/event.rb +15 -8
  39. data/lib/minfraud/components/order.rb +4 -1
  40. data/lib/minfraud/components/payment.rb +138 -14
  41. data/lib/minfraud/components/report/transaction.rb +69 -0
  42. data/lib/minfraud/components/shipping.rb +2 -4
  43. data/lib/minfraud/components/shopping_cart.rb +4 -1
  44. data/lib/minfraud/components/shopping_cart_item.rb +2 -2
  45. data/lib/minfraud/enum.rb +7 -4
  46. data/lib/minfraud/error_handler.rb +29 -9
  47. data/lib/minfraud/errors.rb +2 -0
  48. data/lib/minfraud/http_service.rb +13 -4
  49. data/lib/minfraud/http_service/request.rb +4 -1
  50. data/lib/minfraud/http_service/response.rb +40 -6
  51. data/lib/minfraud/model/abstract.rb +20 -0
  52. data/lib/minfraud/model/address.rb +52 -0
  53. data/lib/minfraud/model/billing_address.rb +11 -0
  54. data/lib/minfraud/model/credit_card.rb +75 -0
  55. data/lib/minfraud/model/device.rb +54 -0
  56. data/lib/minfraud/model/disposition.rb +35 -0
  57. data/lib/minfraud/model/email.rb +54 -0
  58. data/lib/minfraud/model/email_domain.rb +24 -0
  59. data/lib/minfraud/model/error.rb +28 -0
  60. data/lib/minfraud/model/factors.rb +24 -0
  61. data/lib/minfraud/model/geoip2_location.rb +25 -0
  62. data/lib/minfraud/model/insights.rb +68 -0
  63. data/lib/minfraud/model/ip_address.rb +82 -0
  64. data/lib/minfraud/model/issuer.rb +49 -0
  65. data/lib/minfraud/model/score.rb +76 -0
  66. data/lib/minfraud/model/score_ip_address.rb +23 -0
  67. data/lib/minfraud/model/shipping_address.rb +30 -0
  68. data/lib/minfraud/model/subscores.rb +175 -0
  69. data/lib/minfraud/model/warning.rb +63 -0
  70. data/lib/minfraud/report.rb +40 -0
  71. data/lib/minfraud/resolver.rb +16 -13
  72. data/lib/minfraud/version.rb +3 -1
  73. data/minfraud.gemspec +21 -15
  74. metadata +84 -19
@@ -1,22 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Minfraud
2
4
  module ErrorHandler
3
5
  class << self
4
- # Returns a response if status code is 200, rises an error otherwise
6
+ # Returns a response if status code is 2xx, raises an error otherwise
5
7
  # @param [Minfraud::HTTPService::Response] response
6
8
  # @return [Minfraud::HTTPService::Response] if status code is 200
7
- def inspect(response)
8
- return response if response.status == 200
9
+ def examine(response)
10
+ return response if response.status > 199 && response.status < 300
9
11
 
10
- raise *STATUS_CODES.fetch(response.code&.intern, [ServerError, 'Service not available'])
12
+ raise(*STATUS_CODES.fetch(response.code, [ServerError, 'Server error']))
11
13
  end
12
14
 
13
15
  # A hash that maps status codes returned by minFraud with errors & messages
14
16
  STATUS_CODES = {
15
17
  IP_ADDRESS_INVALID: [
16
- ClientError, 'You have no supplied a valid IPv4 or IPv6 address'
18
+ ClientError, 'You have not supplied a valid IPv4 or IPv6 address'
17
19
  ],
18
20
  IP_ADDRESS_REQUIRED: [
19
- ClientError, 'You have not supplied an IP address which is required filed'
21
+ ClientError, 'You have not supplied an IP address which is a required field'
20
22
  ],
21
23
  IP_ADDRESS_RESERVED: [
22
24
  ClientError, 'You have supplied an IP address which is reserved'
@@ -24,14 +26,32 @@ module Minfraud
24
26
  JSON_INVALID: [
25
27
  ClientError, 'JSON body cannot be decoded'
26
28
  ],
29
+ MAXMIND_ID_INVALID: [
30
+ ClientError, 'You have not supplied a valid maxmind_id'
31
+ ],
32
+ MINFRAUD_ID_INVALID: [
33
+ ClientError, 'You have not supplied a valid minfraud_id'
34
+ ],
35
+ PARAMETER_UNKNOWN: [
36
+ ClientError, 'You have supplied an unknown parameter'
37
+ ],
38
+ TAG_REQUIRED: [
39
+ ClientError, 'You have not supplied a tag, which is a required field'
40
+ ],
41
+ TAG_INVALID: [
42
+ ClientError, 'You have not supplied a valid tag'
43
+ ],
44
+ ACCOUNT_ID_REQUIRED: [
45
+ AuthorizationError, 'You have not supplied a account ID'
46
+ ],
27
47
  AUTHORIZATION_INVALID: [
28
- AuthorizationError, 'Invalid license key and / or user id'
48
+ AuthorizationError, 'Invalid license key and / or account ID'
29
49
  ],
30
50
  LICENSE_KEY_REQUIRED: [
31
51
  AuthorizationError, 'You have not supplied a license key'
32
52
  ],
33
53
  USER_ID_REQUIRED: [
34
- AuthorizationError, 'You have not supplied a user id'
54
+ AuthorizationError, 'You have not supplied a account id'
35
55
  ],
36
56
  INSUFFICIENT_FUNDS: [
37
57
  ClientError, 'The license key you have provided does not have a sufficient funds to use this service'
@@ -39,7 +59,7 @@ module Minfraud
39
59
  PERMISSION_REQUIRED: [
40
60
  ClientError, 'You do not have permission to use this service'
41
61
  ]
42
- }
62
+ }.freeze
43
63
  end
44
64
  end
45
65
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Minfraud
2
4
  # A list of Minfraud custom errors
3
5
  class BaseError < StandardError; end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'faraday'
2
4
  require 'faraday_middleware'
3
5
 
@@ -6,20 +8,27 @@ module Minfraud
6
8
  class << self
7
9
  # @return [Hash] default HTTPService configuration
8
10
  def configuration
11
+ server = DEFAULT_SERVER
12
+ if !Minfraud.host.nil?
13
+ server = 'https://' + Minfraud.host + '/minfraud/v2.0'
14
+ end
15
+
9
16
  {
10
17
  middleware: DEFAULT_MIDDLEWARE,
11
- server: DEFAULT_SERVER
18
+ server: server,
12
19
  }
13
20
  end
14
21
  end
15
22
 
16
23
  # Minfraud default middleware stack
17
- DEFAULT_MIDDLEWARE = Proc.new do |builder|
24
+ DEFAULT_MIDDLEWARE = proc do |builder|
18
25
  builder.request :json
19
26
 
20
- builder.basic_auth *::Minfraud.configuration.values
27
+ account_id = Minfraud.account_id
28
+ account_id = Minfraud.user_id if account_id.nil?
29
+
30
+ builder.basic_auth account_id, Minfraud.license_key
21
31
 
22
- builder.response :mashify
23
32
  builder.response :json, content_type: /\bjson$/
24
33
 
25
34
  builder.adapter Faraday.default_adapter
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'faraday'
2
4
 
3
5
  module Minfraud
@@ -14,7 +16,7 @@ module Minfraud
14
16
  # Creates Minfraud::HTTPService::Request instance
15
17
  # @param [Hash] params hash of parameters
16
18
  # @return [Minfraud::HTTPService::Request] Request instance
17
- def initialize(params)
19
+ def initialize(params = {})
18
20
  @middleware = params[:middleware]
19
21
  @server = params[:server]
20
22
  end
@@ -27,6 +29,7 @@ module Minfraud
27
29
  end
28
30
 
29
31
  private
32
+
30
33
  # Creates memoized Faraday::Connection instance
31
34
  # @return [Faraday::Connection] Faraday::Connection instance
32
35
  def adapter
@@ -1,12 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minfraud/model/error'
4
+ require 'minfraud/model/factors'
5
+ require 'minfraud/model/insights'
6
+ require 'minfraud/model/score'
7
+
1
8
  module Minfraud
2
9
  module HTTPService
10
+ # Response class for HTTP requests
3
11
  class Response
4
12
  # @attribute status
5
13
  # @return [Integer] HTTP response status
6
14
  attr_reader :status
7
15
 
8
16
  # @attribute body
9
- # @return [Hash] HTTP response body
17
+ # @return [Minfraud::Model::Score, Minfraud::Model::Insights,
18
+ # Minfraud::Model::Factors] HTTP response body
10
19
  attr_reader :body
11
20
 
12
21
  # @attribute headers
@@ -16,17 +25,42 @@ module Minfraud
16
25
  # Creates Minfraud::HTTPService::Response instance
17
26
  # @param [Hash] params hash of parameters
18
27
  # @return [Minfraud::HTTPService::Response] Response instance
19
- def initialize(params)
28
+ def initialize(params = {})
20
29
  @status = params[:status]
21
- @body = params[:body]
30
+ @body = make_body(
31
+ params[:endpoint],
32
+ params[:body],
33
+ params[:locales]
34
+ )
22
35
  @headers = params[:headers]
23
36
  end
24
37
 
25
- # Returns minFraud specific response code
26
- # @return [String] minFraud specific request code
38
+ # Returns minFraud-specific response code
39
+ # @return [Symbol, nil] minFraud specific request code
27
40
  def code
28
- body.code if body.respond_to?(:code)
41
+ return nil if body.nil?
42
+
43
+ body.code.intern if body.respond_to?(:code) && body.code
29
44
  end
45
+
46
+ private
47
+
48
+ def make_body(endpoint, body, locales)
49
+ if @status != 200
50
+ # Won't be a Hash when the body is not JSON.
51
+ return nil unless body.is_a?(Hash)
52
+
53
+ return Minfraud::Model::Error.new(body)
54
+ end
55
+
56
+ ENDPOINT_TO_CLASS[endpoint].new(body, locales)
57
+ end
58
+
59
+ ENDPOINT_TO_CLASS = {
60
+ factors: Minfraud::Model::Factors,
61
+ insights: Minfraud::Model::Insights,
62
+ score: Minfraud::Model::Score
63
+ }.freeze
30
64
  end
31
65
  end
32
66
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Minfraud
4
+ module Model
5
+ # @!visibility private
6
+ class Abstract
7
+ def initialize(record)
8
+ @record = record
9
+ end
10
+
11
+ protected
12
+
13
+ def get(key)
14
+ return nil if @record.nil? || !@record.key?(key)
15
+
16
+ @record[key]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minfraud/model/abstract'
4
+
5
+ module Minfraud
6
+ module Model
7
+ # Abstract model for a postal address.
8
+ class Address < Abstract
9
+ # The distance in kilometers from the address to the IP location.
10
+ #
11
+ # @return [Integer, nil]
12
+ attr_reader :distance_to_ip_location
13
+
14
+ # This property is true if the address is in the IP country. The property
15
+ # is false when the address is not in the IP country. If the address
16
+ # could not be parsed or was not provided or if the IP address could not
17
+ # be geolocated, the property will be nil.
18
+ #
19
+ # @return [Boolean, nil]
20
+ attr_reader :is_in_ip_country
21
+
22
+ # This property is true if the postal code provided with the address is
23
+ # in the city for the address. The property is false when the postal code
24
+ # is not in the city. If the address was not provided or could not be
25
+ # parsed, the property will be nil.
26
+ #
27
+ # @return [Boolean, nil]
28
+ attr_reader :is_postal_in_city
29
+
30
+ # The latitude associated with the address.
31
+ #
32
+ # @return [Float, nil]
33
+ attr_reader :latitude
34
+
35
+ # The longitude associated with the address.
36
+ #
37
+ # @return [Float, nil]
38
+ attr_reader :longitude
39
+
40
+ # @!visibility private
41
+ def initialize(record)
42
+ super(record)
43
+
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')
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minfraud/model/address'
4
+
5
+ module Minfraud
6
+ module Model
7
+ # Model containing information about the billing address.
8
+ class BillingAddress < Address
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minfraud/model/abstract'
4
+ require 'minfraud/model/issuer'
5
+
6
+ module Minfraud
7
+ module Model
8
+ # Model with details about the credit card used.
9
+ class CreditCard < Abstract
10
+ # The card brand, such as "Visa", "Discover", "American Express", etc.
11
+ #
12
+ # @return [String, nil]
13
+ attr_reader :brand
14
+
15
+ # This property contains the two letter ISO 3166-1 alpha-2 country code
16
+ # (https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) associated with the
17
+ # location of the majority of customers using this credit card as
18
+ # determined by their billing address. In cases where the location of
19
+ # customers is highly mixed, this defaults to the country of the bank
20
+ # issuing the card.
21
+ #
22
+ # @return [String, nil]
23
+ attr_reader :country
24
+
25
+ # This property is true if the card is a business card.
26
+ #
27
+ # @return [Boolean, nil]
28
+ attr_reader :is_business
29
+
30
+ # This property is true if the country of the billing address matches the
31
+ # country of the majority of customers using this credit card. In cases
32
+ # where the location of customers is highly mixed, the match is to the
33
+ # country of the bank issuing the card.
34
+ #
35
+ # @return [Boolean, nil]
36
+ attr_reader :is_issued_in_billing_address_country
37
+
38
+ # This property is true if the card is a prepaid card.
39
+ #
40
+ # @return [Boolean, nil]
41
+ attr_reader :is_prepaid
42
+
43
+ # This property is true if the card is a virtual card.
44
+ #
45
+ # @return [Boolean, nil]
46
+ attr_reader :is_virtual
47
+
48
+ # An object containing information about the credit card issuer.
49
+ #
50
+ # @return [Minfraud::Model::Issuer]
51
+ attr_reader :issuer
52
+
53
+ # The card's type. The valid values are: charge, credit, debit.
54
+ #
55
+ # @return [String, nil]
56
+ attr_reader :type
57
+
58
+ # @!visibility private
59
+ def initialize(record)
60
+ super(record)
61
+
62
+ @brand = get('brand')
63
+ @country = get('country')
64
+ @is_business = get('is_business')
65
+ @is_issued_in_billing_address_country = get(
66
+ 'is_issued_in_billing_address_country'
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')
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minfraud/model/abstract'
4
+
5
+ module Minfraud
6
+ module Model
7
+ # Model with information about the device.
8
+ #
9
+ # In order to receive device output from minFraud Insights or minFraud
10
+ # Factors, you must be using the Device Tracking Add-on
11
+ # (https://dev.maxmind.com/minfraud/device/).
12
+ class Device < Abstract
13
+ # This number represents our confidence that the device_id refers to a
14
+ # unique device as opposed to a cluster of similar devices. A confidence
15
+ # of 0.01 indicates very low confidence that the device is unique,
16
+ # whereas 99 indicates very high confidence.
17
+ #
18
+ # @return [Float, nil]
19
+ attr_reader :confidence
20
+
21
+ # A UUID that MaxMind uses for the device associated with this IP
22
+ # address. Note that many devices cannot be uniquely identified because
23
+ # they are too common (for example, all iPhones of a given model and OS
24
+ # release). In these cases, the minFraud service will simply not return a
25
+ # UUID for that device.
26
+ #
27
+ # @return [String, nil]
28
+ attr_reader :id
29
+
30
+ # This is the date and time of the last sighting of the device. This is
31
+ # an RFC 3339 date-time.
32
+ #
33
+ # @return [String, nil]
34
+ attr_reader :last_seen
35
+
36
+ # This is the local date and time of the transaction in the time zone of
37
+ # the device. This is determined by using the UTC offset associated with
38
+ # the device. This is an RFC 3339 date-time
39
+ #
40
+ # @return [String, nil]
41
+ attr_reader :local_time
42
+
43
+ # @!visibility private
44
+ def initialize(record)
45
+ super(record)
46
+
47
+ @confidence = get('confidence')
48
+ @id = get('id')
49
+ @last_seen = get('last_seen')
50
+ @local_time = get('local_time')
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minfraud/model/abstract'
4
+
5
+ module Minfraud
6
+ module Model
7
+ # Model with the disposition set by custom rules.
8
+ #
9
+ # In order to receive a disposition, you must be using minFraud custom
10
+ # rules.
11
+ class Disposition < Abstract
12
+ # The action to take on the transaction as defined by your custom rules.
13
+ # The current set of values are "accept", "manual_review", and "reject".
14
+ # If you do not have custom rules set up, this will be nil.
15
+ #
16
+ # @return [String, nil]
17
+ attr_reader :action
18
+
19
+ # The reason for the action. The current possible values are
20
+ # "custom_rule", "block_list", and "default". If you do not have custom
21
+ # rules set up, this will be nil.
22
+ #
23
+ # @return [String, nil]
24
+ attr_reader :reason
25
+
26
+ # @!visibility private
27
+ def initialize(record)
28
+ super(record)
29
+
30
+ @action = get('action')
31
+ @reason = get('reason')
32
+ end
33
+ end
34
+ end
35
+ end