minfraud 1.0.3 → 1.4.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 +5 -5
- data/.github/workflows/rubocop.yml +12 -0
- data/.github/workflows/test.yml +32 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +108 -0
- data/CHANGELOG.md +70 -2
- data/CODE_OF_CONDUCT.md +4 -4
- data/Gemfile +11 -2
- data/LICENSE.txt +2 -1
- data/README.dev.md +4 -0
- data/README.md +245 -59
- data/Rakefile +9 -3
- data/bin/console +4 -3
- data/lib/maxmind/geoip2/model/city.rb +99 -0
- data/lib/maxmind/geoip2/model/country.rb +94 -0
- data/lib/maxmind/geoip2/model/insights.rb +38 -0
- data/lib/maxmind/geoip2/record/abstract.rb +46 -0
- data/lib/maxmind/geoip2/record/city.rb +62 -0
- data/lib/maxmind/geoip2/record/continent.rb +61 -0
- data/lib/maxmind/geoip2/record/country.rb +78 -0
- data/lib/maxmind/geoip2/record/location.rb +97 -0
- data/lib/maxmind/geoip2/record/maxmind.rb +41 -0
- data/lib/maxmind/geoip2/record/place.rb +52 -0
- data/lib/maxmind/geoip2/record/postal.rb +54 -0
- data/lib/maxmind/geoip2/record/represented_country.rb +47 -0
- data/lib/maxmind/geoip2/record/subdivision.rb +72 -0
- data/lib/maxmind/geoip2/record/traits.rb +233 -0
- data/lib/minfraud.rb +48 -8
- data/lib/minfraud/assessments.rb +118 -49
- data/lib/minfraud/components/account.rb +31 -9
- data/lib/minfraud/components/addressable.rb +73 -26
- data/lib/minfraud/components/base.rb +35 -11
- data/lib/minfraud/components/billing.rb +5 -0
- data/lib/minfraud/components/credit_card.rb +64 -20
- data/lib/minfraud/components/custom_inputs.rb +25 -0
- data/lib/minfraud/components/device.rb +51 -10
- data/lib/minfraud/components/email.rb +29 -7
- data/lib/minfraud/components/event.rb +60 -13
- data/lib/minfraud/components/order.rb +60 -22
- data/lib/minfraud/components/payment.rb +166 -21
- data/lib/minfraud/components/report/transaction.rb +80 -0
- 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 +45 -18
- data/lib/minfraud/errors.rb +22 -2
- data/lib/minfraud/http_service.rb +22 -8
- data/lib/minfraud/http_service/request.rb +19 -18
- data/lib/minfraud/http_service/response.rb +49 -12
- data/lib/minfraud/model/abstract.rb +20 -0
- data/lib/minfraud/model/address.rb +52 -0
- data/lib/minfraud/model/billing_address.rb +11 -0
- data/lib/minfraud/model/credit_card.rb +75 -0
- data/lib/minfraud/model/device.rb +54 -0
- data/lib/minfraud/model/disposition.rb +35 -0
- data/lib/minfraud/model/email.rb +54 -0
- data/lib/minfraud/model/email_domain.rb +24 -0
- data/lib/minfraud/model/error.rb +28 -0
- data/lib/minfraud/model/factors.rb +24 -0
- data/lib/minfraud/model/geoip2_location.rb +25 -0
- data/lib/minfraud/model/insights.rb +68 -0
- data/lib/minfraud/model/ip_address.rb +82 -0
- data/lib/minfraud/model/issuer.rb +49 -0
- data/lib/minfraud/model/score.rb +76 -0
- data/lib/minfraud/model/score_ip_address.rb +23 -0
- data/lib/minfraud/model/shipping_address.rb +30 -0
- data/lib/minfraud/model/subscores.rb +178 -0
- data/lib/minfraud/model/warning.rb +63 -0
- data/lib/minfraud/report.rb +58 -0
- data/lib/minfraud/resolver.rb +25 -16
- data/lib/minfraud/validates.rb +187 -0
- data/lib/minfraud/version.rb +4 -1
- data/minfraud.gemspec +23 -18
- metadata +113 -39
- data/.travis.yml +0 -5
@@ -1,37 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Minfraud
|
4
|
+
# ErrorHandler provides a method to raise exceptions on errors.
|
2
5
|
module ErrorHandler
|
3
6
|
class << self
|
4
|
-
#
|
5
|
-
#
|
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.
|
22
|
+
def examine(response)
|
23
|
+
return response if response.status > 199 && response.status < 300
|
9
24
|
|
10
|
-
raise
|
25
|
+
raise(*STATUS_CODES.fetch(response.code, [ServerError, 'Server error']))
|
11
26
|
end
|
12
27
|
|
13
|
-
#
|
28
|
+
# @!visibility private
|
14
29
|
STATUS_CODES = {
|
15
|
-
|
16
|
-
ClientError, '
|
30
|
+
JSON_INVALID: [
|
31
|
+
ClientError, 'JSON body cannot be decoded'
|
17
32
|
],
|
18
|
-
|
19
|
-
ClientError,
|
33
|
+
MAXMIND_ID_INVALID: [
|
34
|
+
ClientError, 'You have not supplied a valid maxmind_id'
|
20
35
|
],
|
21
|
-
|
22
|
-
ClientError, 'You have supplied
|
36
|
+
MINFRAUD_ID_INVALID: [
|
37
|
+
ClientError, 'You have not supplied a valid minfraud_id'
|
23
38
|
],
|
24
|
-
|
25
|
-
ClientError, '
|
39
|
+
PARAMETER_UNKNOWN: [
|
40
|
+
ClientError, 'You have supplied an unknown parameter'
|
41
|
+
],
|
42
|
+
REQUEST_INVALID: [
|
43
|
+
ClientError, 'The request did not contain any valid input values.'
|
44
|
+
],
|
45
|
+
TAG_REQUIRED: [
|
46
|
+
ClientError, 'You have not supplied a tag, which is a required field'
|
47
|
+
],
|
48
|
+
TAG_INVALID: [
|
49
|
+
ClientError, 'You have not supplied a valid tag'
|
50
|
+
],
|
51
|
+
ACCOUNT_ID_REQUIRED: [
|
52
|
+
AuthorizationError, 'You have not supplied a account ID'
|
26
53
|
],
|
27
54
|
AUTHORIZATION_INVALID: [
|
28
|
-
AuthorizationError, 'Invalid license key and / or
|
55
|
+
AuthorizationError, 'Invalid license key and / or account ID'
|
29
56
|
],
|
30
57
|
LICENSE_KEY_REQUIRED: [
|
31
58
|
AuthorizationError, 'You have not supplied a license key'
|
32
59
|
],
|
33
60
|
USER_ID_REQUIRED: [
|
34
|
-
AuthorizationError, 'You have not supplied a
|
61
|
+
AuthorizationError, 'You have not supplied a account id'
|
35
62
|
],
|
36
63
|
INSUFFICIENT_FUNDS: [
|
37
64
|
ClientError, 'The license key you have provided does not have a sufficient funds to use this service'
|
@@ -39,7 +66,7 @@ module Minfraud
|
|
39
66
|
PERMISSION_REQUIRED: [
|
40
67
|
ClientError, 'You do not have permission to use this service'
|
41
68
|
]
|
42
|
-
}
|
69
|
+
}.freeze
|
43
70
|
end
|
44
71
|
end
|
45
72
|
end
|
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,31 +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
|
-
builder.response :mashify
|
23
35
|
builder.response :json, content_type: /\bjson$/
|
24
36
|
|
25
|
-
builder.adapter
|
37
|
+
builder.adapter :net_http_persistent, pool_size: 5 do |http|
|
38
|
+
http.idle_timeout = 30
|
39
|
+
end
|
26
40
|
end
|
27
41
|
|
28
|
-
#
|
42
|
+
# Default base URL for minFraud.
|
29
43
|
DEFAULT_SERVER = 'https://minfraud.maxmind.com/minfraud/v2.0'
|
30
44
|
end
|
31
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
|
@@ -1,32 +1,69 @@
|
|
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
|
-
#
|
5
|
-
#
|
12
|
+
# HTTP response status.
|
13
|
+
#
|
14
|
+
# @return [Integer, nil]
|
6
15
|
attr_reader :status
|
7
16
|
|
8
|
-
#
|
9
|
-
#
|
17
|
+
# HTTP response model.
|
18
|
+
#
|
19
|
+
# @return [Minfraud::Model::Score, Minfraud::Model::Insights,
|
20
|
+
# Minfraud::Model::Factors, nil]
|
10
21
|
attr_reader :body
|
11
22
|
|
12
|
-
#
|
13
|
-
#
|
23
|
+
# HTTP response headers.
|
24
|
+
#
|
25
|
+
# @return [Hash, nil]
|
14
26
|
attr_reader :headers
|
15
27
|
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# @return [Minfraud::HTTPService::Response] Response instance
|
28
|
+
# @param params [Hash] Hash of parameters. +:status+, +:endpoint+,
|
29
|
+
# +:body+, +:locales+, and +:headers+ are used.
|
19
30
|
def initialize(params = {})
|
20
31
|
@status = params[:status]
|
21
|
-
@body =
|
32
|
+
@body = make_body(
|
33
|
+
params[:endpoint],
|
34
|
+
params[:body],
|
35
|
+
params[:locales]
|
36
|
+
)
|
22
37
|
@headers = params[:headers]
|
23
38
|
end
|
24
39
|
|
25
|
-
#
|
26
|
-
#
|
40
|
+
# Return the minFraud-specific response code.
|
41
|
+
#
|
42
|
+
# @return [Symbol, nil]
|
27
43
|
def code
|
44
|
+
return nil if body.nil?
|
45
|
+
|
28
46
|
body.code.intern if body.respond_to?(:code) && body.code
|
29
47
|
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def make_body(endpoint, body, locales)
|
52
|
+
if @status != 200
|
53
|
+
# Won't be a Hash when the body is not JSON.
|
54
|
+
return nil unless body.is_a?(Hash)
|
55
|
+
|
56
|
+
return Minfraud::Model::Error.new(body)
|
57
|
+
end
|
58
|
+
|
59
|
+
ENDPOINT_TO_CLASS[endpoint].new(body, locales)
|
60
|
+
end
|
61
|
+
|
62
|
+
ENDPOINT_TO_CLASS = {
|
63
|
+
factors: Minfraud::Model::Factors,
|
64
|
+
insights: Minfraud::Model::Insights,
|
65
|
+
score: Minfraud::Model::Score
|
66
|
+
}.freeze
|
30
67
|
end
|
31
68
|
end
|
32
69
|
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,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
|