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,14 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Minfraud
|
2
4
|
module Components
|
5
|
+
# Shipping corresponds to the shipping object of a minFraud request.
|
6
|
+
#
|
7
|
+
# @see https://dev.maxmind.com/minfraud/#Shipping_(/shipping)
|
3
8
|
class Shipping < Addressable
|
4
9
|
include ::Minfraud::Enum
|
5
|
-
|
6
|
-
#
|
10
|
+
|
11
|
+
# The shipping delivery speed for the order. Must be one of +:same_day+,
|
12
|
+
# +:overnight+, +:expedited+, or +:standard+.
|
13
|
+
#
|
14
|
+
# @!attribute delivery_speed
|
15
|
+
#
|
16
|
+
# @return [Symbol, nil]
|
7
17
|
enum_accessor :delivery_speed, [:same_day, :overnight, :expedited, :standard]
|
8
18
|
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# @return [Minfraud::Components::Shipping] Shipping instance
|
19
|
+
# @param params [Hash] Hash of parameters. Each key/value should
|
20
|
+
# correspond to one of the available attributes.
|
12
21
|
def initialize(params = {})
|
13
22
|
self.delivery_speed = params[:delivery_speed]
|
14
23
|
super
|
@@ -1,27 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Minfraud
|
2
4
|
module Components
|
5
|
+
# ShoppingCart corresponds to the shopping_cart object of a minFraud
|
6
|
+
# request.
|
7
|
+
#
|
8
|
+
# @see https://dev.maxmind.com/minfraud/#Shopping_Cart_(/shoppingcart)
|
3
9
|
class ShoppingCart < Base
|
4
|
-
#
|
5
|
-
#
|
6
|
-
|
10
|
+
# An array of Minfraud::Components::ShoppingCartItem instances.
|
11
|
+
#
|
12
|
+
# @return [Array<Minfraud::Components::ShoppingCartItem>]
|
7
13
|
attr_accessor :items
|
8
|
-
|
9
|
-
# @param
|
10
|
-
#
|
11
|
-
|
14
|
+
|
15
|
+
# @param params [Array] Array of shopping cart items. You may provide
|
16
|
+
# each item as either a Hash where each key is a symbol corresponding
|
17
|
+
# to an item's field, or as a Minfraud:::Components::ShoppingCartItem
|
18
|
+
# object.
|
19
|
+
def initialize(params = [])
|
12
20
|
@items = params.map(&method(:resolve))
|
13
21
|
end
|
14
22
|
|
15
|
-
#
|
16
|
-
|
23
|
+
# A JSON representation of Minfraud::Components::ShoppingCart items.
|
24
|
+
#
|
25
|
+
# @return [Array]
|
26
|
+
def to_json(*_args)
|
17
27
|
@items.map(&:to_json)
|
18
28
|
end
|
19
29
|
|
20
30
|
private
|
21
31
|
|
22
|
-
# @param [Hash] params hash of parameters for Minfraud::Components::ShoppingCartItem
|
23
|
-
# or Minfraud::Components::ShoppingCartItem instance
|
24
|
-
# @return [Minfraud::Components::ShoppingCart] ShoppingCart instance
|
25
32
|
def resolve(params)
|
26
33
|
params.is_a?(ShoppingCartItem) ? params : ShoppingCartItem.new(params)
|
27
34
|
end
|
@@ -1,33 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Minfraud
|
2
4
|
module Components
|
5
|
+
# ShoppingCartItem corresponds to objects in the shopping_cart object
|
6
|
+
# of a minFraud request.
|
7
|
+
#
|
8
|
+
# @see https://dev.maxmind.com/minfraud/#Shopping_Cart_Item
|
3
9
|
class ShoppingCartItem < Base
|
4
|
-
|
5
|
-
|
10
|
+
include Minfraud::Validates
|
11
|
+
|
12
|
+
# The category of the item. This can also be a hashed value; see link.
|
13
|
+
#
|
14
|
+
# @see https://dev.maxmind.com/minfraud/#cart-hashing
|
15
|
+
#
|
16
|
+
# @return [String, nil]
|
6
17
|
attr_accessor :category
|
7
18
|
|
8
|
-
#
|
9
|
-
#
|
19
|
+
# The internal ID of the item. This can also be a hashed value; see link.
|
20
|
+
#
|
21
|
+
# @see https://dev.maxmind.com/minfraud/#cart-hashing
|
22
|
+
#
|
23
|
+
# @return [String, nil]
|
10
24
|
attr_accessor :item_id
|
11
25
|
|
12
|
-
#
|
13
|
-
#
|
26
|
+
# The quantity of the item in the shopping cart. The value must be at
|
27
|
+
# least 0, at most 10^13-1, and have no fractional part.
|
28
|
+
#
|
29
|
+
# @return [Integer, nil]
|
14
30
|
attr_accessor :quantity
|
15
31
|
|
16
|
-
#
|
17
|
-
#
|
32
|
+
# The per-unit price of this item in the shopping cart. This should use
|
33
|
+
# the same currency as the order currency. The value must be at least 0
|
34
|
+
# and at most 1e14 - 1.
|
35
|
+
#
|
36
|
+
# @return [Float, nil]
|
18
37
|
attr_accessor :price
|
19
38
|
|
20
|
-
#
|
21
|
-
#
|
22
|
-
# @return [Minfraud::Components::ShoppingCartItem] ShoppingCartItem instance
|
39
|
+
# @param params [Hash] Hash of parameters. Each key/value should
|
40
|
+
# correspond to one of the available attributes.
|
23
41
|
def initialize(params = {})
|
24
42
|
@category = params[:category]
|
25
43
|
@item_id = params[:item_id]
|
26
44
|
@quantity = params[:quantity]
|
27
45
|
@price = params[:price]
|
46
|
+
|
47
|
+
validate
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def validate
|
53
|
+
return if !Minfraud.enable_validation
|
54
|
+
|
55
|
+
validate_string('category', 255, @category)
|
56
|
+
validate_string('item_id', 255, @item_id)
|
57
|
+
validate_nonnegative_integer('quantity', @quantity)
|
58
|
+
validate_nonnegative_number('price', @price)
|
28
59
|
end
|
29
60
|
end
|
30
61
|
end
|
31
62
|
end
|
32
|
-
|
33
|
-
|
data/lib/minfraud/enum.rb
CHANGED
@@ -1,19 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Minfraud
|
4
|
+
# Enum provides helpers for working with attributes with enumerated types.
|
2
5
|
module Enum
|
3
6
|
def self.included(base)
|
4
7
|
base.extend(ClassMethods)
|
5
8
|
end
|
6
9
|
|
10
|
+
# ClassMethods provides helpers for working with attributes with enumerated
|
11
|
+
# types.
|
7
12
|
module ClassMethods
|
8
|
-
# Returns a hash
|
9
|
-
#
|
13
|
+
# Returns a hash in the following format: attribute_name =>
|
14
|
+
# permitted_values
|
15
|
+
#
|
16
|
+
# @return [Hash]
|
10
17
|
def mapping
|
11
18
|
@mapping ||= {}
|
12
19
|
end
|
13
20
|
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# @param [
|
21
|
+
# Create a set of methods for enum-like behavior of the attribute.
|
22
|
+
#
|
23
|
+
# @param attribute [Symbol] The attribute name.
|
24
|
+
#
|
25
|
+
# @param assignable_values [Array] The set of permitted values.
|
26
|
+
#
|
27
|
+
# @return [nil]
|
17
28
|
def enum_accessor(attribute, assignable_values)
|
18
29
|
mapping[attribute] = assignable_values.map(&:intern)
|
19
30
|
|
@@ -21,13 +32,16 @@ module Minfraud
|
|
21
32
|
define_method("#{attribute}_values") { mapping[attribute] }
|
22
33
|
end
|
23
34
|
|
24
|
-
|
25
|
-
define_method(
|
35
|
+
class_eval do
|
36
|
+
define_method(attribute.to_s) { instance_variable_get("@#{attribute}") }
|
26
37
|
define_method "#{attribute}=" do |value|
|
27
|
-
raise NotEnumValueError,
|
38
|
+
raise NotEnumValueError, 'Value is not permitted' if value && !self.class.mapping[attribute].include?(value.intern)
|
39
|
+
|
28
40
|
instance_variable_set("@#{attribute}", value ? value.intern : nil)
|
29
41
|
end
|
30
42
|
end
|
43
|
+
|
44
|
+
nil
|
31
45
|
end
|
32
46
|
end
|
33
47
|
end
|
@@ -1,62 +1,69 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Minfraud
|
4
|
+
# ErrorHandler provides a method to raise exceptions on errors.
|
4
5
|
module ErrorHandler
|
5
6
|
class << self
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
7
|
+
# Return the response if the HTTP status code is 2xx. Otherwise raise
|
8
|
+
# an error.
|
9
|
+
#
|
10
|
+
# @param response [Minfraud::HTTPService::Response]
|
11
|
+
#
|
12
|
+
# @return [Minfraud::HTTPService::Response]
|
13
|
+
#
|
14
|
+
# @raise [Minfraud::AuthorizationError] If there was an authentication
|
15
|
+
# problem.
|
16
|
+
#
|
17
|
+
# @raise [Minfraud::ClientError] If there was a critical problem with one
|
18
|
+
# of your inputs.
|
19
|
+
#
|
20
|
+
# @raise [Minfraud::ServerError] If the server reported an error of some
|
21
|
+
# kind.
|
9
22
|
def examine(response)
|
10
23
|
return response if response.status > 199 && response.status < 300
|
11
24
|
|
12
|
-
raise
|
25
|
+
raise(*STATUS_CODES.fetch(response.code, [ServerError, 'Server error']))
|
13
26
|
end
|
14
27
|
|
15
|
-
#
|
28
|
+
# @!visibility private
|
16
29
|
STATUS_CODES = {
|
17
|
-
|
18
|
-
ClientError, 'You have not supplied a valid IPv4 or IPv6 address'
|
19
|
-
],
|
20
|
-
IP_ADDRESS_REQUIRED: [
|
21
|
-
ClientError, 'You have not supplied an IP address which is a required field'
|
22
|
-
],
|
23
|
-
IP_ADDRESS_RESERVED: [
|
24
|
-
ClientError, 'You have supplied an IP address which is reserved'
|
25
|
-
],
|
26
|
-
JSON_INVALID: [
|
30
|
+
JSON_INVALID: [
|
27
31
|
ClientError, 'JSON body cannot be decoded'
|
28
32
|
],
|
29
|
-
MAXMIND_ID_INVALID:
|
33
|
+
MAXMIND_ID_INVALID: [
|
30
34
|
ClientError, 'You have not supplied a valid maxmind_id'
|
31
35
|
],
|
32
|
-
MINFRAUD_ID_INVALID:
|
36
|
+
MINFRAUD_ID_INVALID: [
|
33
37
|
ClientError, 'You have not supplied a valid minfraud_id'
|
34
38
|
],
|
35
|
-
PARAMETER_UNKNOWN:
|
39
|
+
PARAMETER_UNKNOWN: [
|
36
40
|
ClientError, 'You have supplied an unknown parameter'
|
37
41
|
],
|
38
|
-
|
42
|
+
REQUEST_INVALID: [
|
43
|
+
ClientError, 'The request did not contain any valid input values.'
|
44
|
+
],
|
45
|
+
TAG_REQUIRED: [
|
39
46
|
ClientError, 'You have not supplied a tag, which is a required field'
|
40
47
|
],
|
41
|
-
TAG_INVALID:
|
48
|
+
TAG_INVALID: [
|
42
49
|
ClientError, 'You have not supplied a valid tag'
|
43
50
|
],
|
44
|
-
ACCOUNT_ID_REQUIRED:
|
51
|
+
ACCOUNT_ID_REQUIRED: [
|
45
52
|
AuthorizationError, 'You have not supplied a account ID'
|
46
53
|
],
|
47
54
|
AUTHORIZATION_INVALID: [
|
48
55
|
AuthorizationError, 'Invalid license key and / or account ID'
|
49
56
|
],
|
50
|
-
LICENSE_KEY_REQUIRED:
|
57
|
+
LICENSE_KEY_REQUIRED: [
|
51
58
|
AuthorizationError, 'You have not supplied a license key'
|
52
59
|
],
|
53
|
-
USER_ID_REQUIRED:
|
60
|
+
USER_ID_REQUIRED: [
|
54
61
|
AuthorizationError, 'You have not supplied a account id'
|
55
62
|
],
|
56
|
-
INSUFFICIENT_FUNDS:
|
63
|
+
INSUFFICIENT_FUNDS: [
|
57
64
|
ClientError, 'The license key you have provided does not have a sufficient funds to use this service'
|
58
65
|
],
|
59
|
-
PERMISSION_REQUIRED:
|
66
|
+
PERMISSION_REQUIRED: [
|
60
67
|
ClientError, 'You do not have permission to use this service'
|
61
68
|
]
|
62
69
|
}.freeze
|
data/lib/minfraud/errors.rb
CHANGED
@@ -1,10 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Minfraud
|
2
|
-
#
|
3
|
-
class BaseError
|
4
|
+
# The base error class for Minfraud exceptions.
|
5
|
+
class BaseError < StandardError; end
|
6
|
+
|
7
|
+
# An error indicating the input value is not valid.
|
8
|
+
class InvalidInputError < BaseError; end
|
4
9
|
|
10
|
+
# An error indicating the value is not valid for the enumerated type.
|
5
11
|
class NotEnumValueError < BaseError; end
|
12
|
+
|
13
|
+
# An error indicating the field is not recognized.
|
6
14
|
class RequestFormatError < BaseError; end
|
15
|
+
|
16
|
+
# An error indicating minFraud cannot serve your request as there is a
|
17
|
+
# problem on the client side.
|
18
|
+
#
|
19
|
+
# For example, this may happen if there is a problem with the format or
|
20
|
+
# contents of your request, if you lack funds to use the service, or if you
|
21
|
+
# don't have permission to use the service.
|
7
22
|
class ClientError < BaseError; end
|
23
|
+
|
24
|
+
# An error indicating there is a problem with authorization or
|
25
|
+
# authentication.
|
8
26
|
class AuthorizationError < BaseError; end
|
27
|
+
|
28
|
+
# An error indicating the server had an error handling the request.
|
9
29
|
class ServerError < BaseError; end
|
10
30
|
end
|
@@ -1,30 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'faraday'
|
2
4
|
require 'faraday_middleware'
|
3
5
|
|
4
6
|
module Minfraud
|
7
|
+
# HTTPService holds the HTTP client configuration.
|
5
8
|
module HTTPService
|
6
9
|
class << self
|
7
|
-
#
|
10
|
+
# The default HTTPService configuration.
|
11
|
+
#
|
12
|
+
# @return [Hash]
|
8
13
|
def configuration
|
14
|
+
server = DEFAULT_SERVER
|
15
|
+
if !Minfraud.host.nil?
|
16
|
+
server = "https://#{Minfraud.host}/minfraud/v2.0"
|
17
|
+
end
|
18
|
+
|
9
19
|
{
|
10
20
|
middleware: DEFAULT_MIDDLEWARE,
|
11
|
-
server:
|
21
|
+
server: server,
|
12
22
|
}
|
13
23
|
end
|
14
24
|
end
|
15
25
|
|
16
|
-
#
|
17
|
-
DEFAULT_MIDDLEWARE =
|
26
|
+
# @!visibility private
|
27
|
+
DEFAULT_MIDDLEWARE = proc do |builder|
|
18
28
|
builder.request :json
|
19
29
|
|
20
|
-
|
30
|
+
account_id = Minfraud.account_id
|
31
|
+
account_id = Minfraud.user_id if account_id.nil?
|
32
|
+
|
33
|
+
builder.basic_auth account_id, Minfraud.license_key
|
21
34
|
|
22
35
|
builder.response :json, content_type: /\bjson$/
|
23
36
|
|
24
|
-
builder.adapter
|
37
|
+
builder.adapter :net_http_persistent, pool_size: 5 do |http|
|
38
|
+
http.idle_timeout = 30
|
39
|
+
end
|
25
40
|
end
|
26
41
|
|
27
|
-
#
|
28
|
-
DEFAULT_SERVER = 'https://minfraud.maxmind.com/minfraud/v2.0'
|
42
|
+
# Default base URL for minFraud.
|
43
|
+
DEFAULT_SERVER = 'https://minfraud.maxmind.com/minfraud/v2.0'
|
29
44
|
end
|
30
45
|
end
|
@@ -1,36 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'faraday'
|
2
4
|
|
3
5
|
module Minfraud
|
4
6
|
module HTTPService
|
7
|
+
# Request performs HTTP requests.
|
5
8
|
class Request
|
6
|
-
#
|
7
|
-
#
|
9
|
+
# A proc containing Faraday configuration.
|
10
|
+
#
|
11
|
+
# @return [Proc, nil]
|
8
12
|
attr_reader :middleware
|
9
13
|
|
10
|
-
#
|
11
|
-
#
|
14
|
+
# The API endpoint.
|
15
|
+
#
|
16
|
+
# @return [String, nil]
|
12
17
|
attr_reader :server
|
13
18
|
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# @return [Minfraud::HTTPService::Request] Request instance
|
19
|
+
# @param params [Hash] Hash of parameters. Each key/value should
|
20
|
+
# correspond to one of the available attributes.
|
17
21
|
def initialize(params = {})
|
18
22
|
@middleware = params[:middleware]
|
19
23
|
@server = params[:server]
|
20
24
|
end
|
21
25
|
|
22
|
-
#
|
23
|
-
#
|
24
|
-
# @
|
26
|
+
# Perform an HTTP request to the specified endpoint with given body.
|
27
|
+
#
|
28
|
+
# @param params [Hash] Hash of parameters, including +:verb+,
|
29
|
+
# +:endpoint+, and +:body+.
|
30
|
+
#
|
31
|
+
# @return [Farday::Response]
|
25
32
|
def perform(params)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
private
|
30
|
-
# Creates memoized Faraday::Connection instance
|
31
|
-
# @return [Faraday::Connection] Faraday::Connection instance
|
32
|
-
def adapter
|
33
|
-
@adapter ||= Faraday.new(server, {}, &middleware)
|
33
|
+
connection = Minfraud.connection
|
34
|
+
connection.send(*params.values_at(:verb, :endpoint, :body))
|
34
35
|
end
|
35
36
|
end
|
36
37
|
end
|