maxmind 0.4.2 → 0.4.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +5 -0
- data/Gemfile +9 -2
- data/Guardfile +22 -0
- data/LICENSE +1 -1
- data/README.md +57 -18
- data/examples/chargeback_example.rb +20 -0
- data/lib/maxmind/chargeback_request.rb +94 -0
- data/lib/maxmind/chargeback_response.rb +12 -0
- data/lib/maxmind/request.rb +27 -29
- data/lib/maxmind/response.rb +12 -8
- data/lib/maxmind/version.rb +2 -2
- data/lib/maxmind.rb +15 -8
- data/maxmind.gemspec +11 -18
- data/spec/data/response.txt +1 -1
- data/spec/maxmind/chargeback_request_spec.rb +26 -0
- data/spec/maxmind/chargeback_response_spec.rb +25 -0
- data/spec/maxmind/request_spec.rb +48 -13
- data/spec/maxmind/response_spec.rb +28 -20
- data/spec/spec_helper.rb +5 -14
- metadata +20 -86
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4608e9c60c8244b7b82c9a95add791a1b0d4f718
|
4
|
+
data.tar.gz: 7e2da7ff1682d4db6c238b0a56480b3014265fdb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7a9e248e97806a9391aa3e25d3c5c68e323d08b3ba28525bcf9da55fd2b0eecafe01c7ba071ff0db5ad9c0f1a13e66d4e0afce2e7db14abe7427f7ae7912a939
|
7
|
+
data.tar.gz: 17a3e05790a99d970ec19b08b0b932f5798bd4be29f47fc595c8437a33245c60540b71cdc5b2a18e2afe04f6440ff219df61c9009e1aea92d2cfc8d015a86b07
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/Guardfile
CHANGED
@@ -4,3 +4,25 @@ guard 'rspec', :version => 2, :cli => '--color --format doc' do
|
|
4
4
|
watch('lib/eventricle.rb') { "spec/eventricle.rb" }
|
5
5
|
watch('spec/spec_helper.rb') { "spec" }
|
6
6
|
end
|
7
|
+
|
8
|
+
guard :rspec do
|
9
|
+
watch(%r{^spec/.+_spec\.rb$})
|
10
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
11
|
+
watch('spec/spec_helper.rb') { "spec" }
|
12
|
+
|
13
|
+
# Rails example
|
14
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
15
|
+
watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
16
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
17
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
18
|
+
watch('config/routes.rb') { "spec/routing" }
|
19
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
20
|
+
|
21
|
+
# Capybara features specs
|
22
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
23
|
+
|
24
|
+
# Turnip features and steps
|
25
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
26
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
27
|
+
end
|
28
|
+
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
maxmind
|
2
2
|
==========
|
3
3
|
|
4
|
-
|
4
|
+
An unofficial wrapper around MaxMind's minFraud anti-fraud service.
|
5
5
|
|
6
|
+
For MaxMind's Proxy Detection Service, see this gem: [https://github.com/eric-smartlove/maxmind\_proxy\_detection](https://github.com/eric-smartlove/maxmind_proxy_detection)
|
6
7
|
|
7
8
|
Installation
|
8
9
|
------------
|
@@ -15,7 +16,7 @@ Tests
|
|
15
16
|
------------
|
16
17
|
|
17
18
|
bundle install
|
18
|
-
guard
|
19
|
+
bundle exec guard
|
19
20
|
|
20
21
|
Dependencies
|
21
22
|
------------
|
@@ -27,7 +28,7 @@ Running Tests
|
|
27
28
|
|
28
29
|
Run `bundle install` to make sure you have all the dependencies. Once that's done, run:
|
29
30
|
|
30
|
-
rake
|
31
|
+
rake spec
|
31
32
|
|
32
33
|
Usage
|
33
34
|
-----
|
@@ -38,11 +39,7 @@ These are the only required fields to acquire a response from MaxMind.
|
|
38
39
|
require 'maxmind'
|
39
40
|
Maxmind.license_key = 'LICENSE_KEY'
|
40
41
|
request = Maxmind::Request.new(
|
41
|
-
:client_ip => '24.24.24.24'
|
42
|
-
:city => 'New York',
|
43
|
-
:region => 'NY',
|
44
|
-
:postal => '11434',
|
45
|
-
:country => 'US'
|
42
|
+
:client_ip => '24.24.24.24'
|
46
43
|
)
|
47
44
|
|
48
45
|
response = request.process!
|
@@ -104,9 +101,6 @@ This is every field available.
|
|
104
101
|
|
105
102
|
response = request.process!
|
106
103
|
|
107
|
-
|
108
|
-
Also see examples/example.rb
|
109
|
-
|
110
104
|
TODO
|
111
105
|
----
|
112
106
|
* Improve specs (eg, test server failover)
|
@@ -115,15 +109,60 @@ Reference
|
|
115
109
|
---------
|
116
110
|
[minFraud API Reference](http://www.maxmind.com/app/ccv)
|
117
111
|
|
112
|
+
Also see examples/example.rb
|
113
|
+
|
114
|
+
Chargeback Service
|
115
|
+
------------------
|
116
|
+
|
117
|
+
You can help improve the Minfraud service by reporting instances of fraud. Only the IP address of a suspected fraudulent order is required, but you can pass additional information. Note that your Maxmind User ID is required in addition to your license key.
|
118
|
+
|
119
|
+
Chargeback Service Usage
|
120
|
+
------------------------
|
121
|
+
|
122
|
+
### Minimum Required ###
|
123
|
+
These are the only required fields to acquire a response from MaxMind.
|
124
|
+
|
125
|
+
require 'maxmind'
|
126
|
+
Maxmind.license_key = 'LICENSE_KEY'
|
127
|
+
Maxmind.user_id = 'MAXMIND_USER_ID'
|
128
|
+
request = Maxmind::ChargebackRequest.new(
|
129
|
+
:client_ip => '24.24.24.24'
|
130
|
+
)
|
131
|
+
|
132
|
+
response = request.process!
|
133
|
+
|
134
|
+
|
135
|
+
### Recommended ###
|
136
|
+
For increased accuracy, these are the recommended fields to submit to MaxMind. The additional
|
137
|
+
fields here are optional and can be all or none.
|
138
|
+
|
139
|
+
require 'maxmind'
|
140
|
+
Maxmind.license_key = 'LICENSE_KEY'
|
141
|
+
Maxmind.user_id = 'MAXMIND_USER_ID'
|
142
|
+
request = Maxmind::ChargebackRequest.new(
|
143
|
+
:client_ip => '24.24.24.24',
|
144
|
+
:chargeback_code => 'Fraud',
|
145
|
+
:fraud_score => 'suspected_fraud',
|
146
|
+
:maxmind_id => 'KW36L83C',
|
147
|
+
:transaction_id => '12345'
|
148
|
+
)
|
149
|
+
|
150
|
+
response = request.process!
|
151
|
+
|
152
|
+
[minFraud Chargeback reference](http://dev.maxmind.com/minfraud/chargeback)
|
153
|
+
|
118
154
|
Contributors
|
119
155
|
------------
|
120
|
-
Sam Oliver <sam@samoliver.com>
|
121
|
-
Nick Wilson <nick@di.fm>
|
122
|
-
Wolfram Arnold <wolfram@rubyfocus.biz>
|
123
|
-
Jonathan Lim <snowblink@gmail.com>
|
124
|
-
Tom Blomfield
|
125
|
-
Thomas Morgan
|
126
|
-
Tinu Cleatus <tinu.cleatus@me.com>
|
156
|
+
* Sam Oliver <sam@samoliver.com>
|
157
|
+
* Nick Wilson <nick@di.fm>
|
158
|
+
* Wolfram Arnold <wolfram@rubyfocus.biz>
|
159
|
+
* Jonathan Lim <snowblink@gmail.com>
|
160
|
+
* Tom Blomfield
|
161
|
+
* Thomas Morgan
|
162
|
+
* Tinu Cleatus <tinu.cleatus@me.com>
|
163
|
+
* Don Pflaster <dpflaster@gmail.com>
|
164
|
+
* Igor Pstyga
|
165
|
+
* Jack Kelly <jack@trikeapps.com>
|
127
166
|
|
128
167
|
Thanks to all :)
|
129
168
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'lib/maxmind')
|
3
|
+
|
4
|
+
required_fields = {
|
5
|
+
:client_ip => '24.24.24.24'
|
6
|
+
}
|
7
|
+
|
8
|
+
recommended_fields = {
|
9
|
+
:client_ip => '24.24.24.24',
|
10
|
+
:chargeback_code => 'Fraud',
|
11
|
+
:fraud_score => 'suspected_fraud',
|
12
|
+
:maxmind_id => 'KW36L83C',
|
13
|
+
:transaction_id => '12345'
|
14
|
+
}
|
15
|
+
|
16
|
+
Maxmind.license_key = 'LICENSE_KEY'
|
17
|
+
Maxmind.user_id = 'MAXMIND_USER_ID'
|
18
|
+
request = Maxmind::ChargebackRequest.new(required_fields.merge(recommended_fields))
|
19
|
+
response = request.process!
|
20
|
+
pp response
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Maxmind
|
2
|
+
class ChargebackRequest
|
3
|
+
DefaultTimeout = 60
|
4
|
+
|
5
|
+
# optionally set a default request type (one of 'standard' or 'premium')
|
6
|
+
# Maxmind's default behavior is to use premium if you have credits, else use standard
|
7
|
+
class << self
|
8
|
+
attr_accessor :default_request_type
|
9
|
+
attr_accessor :timeout
|
10
|
+
end
|
11
|
+
|
12
|
+
# Required Fields
|
13
|
+
attr_accessor :client_ip
|
14
|
+
|
15
|
+
# Optional Fields
|
16
|
+
attr_accessor :chargeback_code, :fraud_score, :maxmind_id, :transaction_id
|
17
|
+
|
18
|
+
def initialize(attrs={})
|
19
|
+
self.attributes = attrs
|
20
|
+
end
|
21
|
+
|
22
|
+
def attributes=(attrs={})
|
23
|
+
attrs.each do |k, v|
|
24
|
+
self.send("#{k}=", v)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def process!
|
29
|
+
resp = post(query)
|
30
|
+
Maxmind::ChargebackResponse.new(resp.message, resp.code)
|
31
|
+
end
|
32
|
+
|
33
|
+
def process
|
34
|
+
process!
|
35
|
+
rescue Exception => e
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
def query
|
40
|
+
validate
|
41
|
+
|
42
|
+
required_fields = {
|
43
|
+
:ip_address => @client_ip,
|
44
|
+
}
|
45
|
+
|
46
|
+
optional_fields = {
|
47
|
+
:chargeback_code => @chargeback_code,
|
48
|
+
:fraud_score => @fraud_score,
|
49
|
+
:maxmind_id => @maxmind_id,
|
50
|
+
:transaction_id => @transaction_id
|
51
|
+
}
|
52
|
+
|
53
|
+
field_set = required_fields.merge(optional_fields)
|
54
|
+
field_set.reject {|k, v| v.nil? }.to_json
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Upon a failure at the first URL, will automatically retry with the
|
60
|
+
# second & third ones before finally raising an exception
|
61
|
+
# Returns an HTTPResponse object
|
62
|
+
def post(query_params)
|
63
|
+
servers ||= SERVERS.map{|hostname| "https://#{hostname}/minfraud/chargeback"}
|
64
|
+
url = URI.parse(servers.shift)
|
65
|
+
|
66
|
+
req = Net::HTTP::Post.new(url.path, initheader = {'Content-Type' =>'application/json'})
|
67
|
+
req.basic_auth Maxmind::user_id, Maxmind::license_key
|
68
|
+
req.body = query_params
|
69
|
+
|
70
|
+
h = Net::HTTP.new(url.host, url.port)
|
71
|
+
h.use_ssl = true
|
72
|
+
h.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
73
|
+
|
74
|
+
# set some timeouts
|
75
|
+
h.open_timeout = 60 # this blocks forever by default, lets be a bit less crazy.
|
76
|
+
h.read_timeout = self.class.timeout || DefaultTimeout
|
77
|
+
h.ssl_timeout = self.class.timeout || DefaultTimeout
|
78
|
+
|
79
|
+
h.start { |http| http.request(req) }
|
80
|
+
|
81
|
+
rescue Exception => e
|
82
|
+
retry if servers.size > 0
|
83
|
+
raise e
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
def validate
|
89
|
+
raise ArgumentError, 'License key is required' unless Maxmind::license_key
|
90
|
+
raise ArgumentError, 'User ID is required' unless Maxmind::user_id
|
91
|
+
raise ArgumentError, 'IP address is required' unless client_ip
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Maxmind
|
2
|
+
class ChargebackResponse
|
3
|
+
attr_accessor :attributes
|
4
|
+
attr_reader :response, :http_code
|
5
|
+
|
6
|
+
def initialize(response = nil, http_code = nil)
|
7
|
+
raise ArgumentError, 'Missing response string' unless response
|
8
|
+
@response = response
|
9
|
+
@http_code = http_code.to_i if http_code
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/maxmind/request.rb
CHANGED
@@ -1,11 +1,4 @@
|
|
1
1
|
module Maxmind
|
2
|
-
# Your license key
|
3
|
-
class << self
|
4
|
-
attr_accessor :license_key
|
5
|
-
end
|
6
|
-
|
7
|
-
SERVERS = %w(minfraud.maxmind.com minfraud-us-east.maxmind.com minfraud-us-west.maxmind.com)
|
8
|
-
|
9
2
|
class Request
|
10
3
|
DefaultTimeout = 60
|
11
4
|
|
@@ -16,7 +9,6 @@ module Maxmind
|
|
16
9
|
attr_accessor :timeout
|
17
10
|
end
|
18
11
|
|
19
|
-
|
20
12
|
# Required Fields
|
21
13
|
attr_accessor :client_ip, :city, :region, :postal, :country
|
22
14
|
|
@@ -25,20 +17,18 @@ module Maxmind
|
|
25
17
|
:forwarded_ip, :email, :username, :password, :transaction_id, :session_id,
|
26
18
|
:shipping_address, :shipping_city, :shipping_region, :shipping_postal,
|
27
19
|
:shipping_country, :user_agent, :accept_language, :order_amount,
|
28
|
-
:order_currency
|
20
|
+
:order_currency, :avs_result, :cvv_result, :txn_type
|
29
21
|
|
30
22
|
def initialize(attrs={})
|
31
23
|
self.attributes = attrs
|
32
24
|
end
|
33
25
|
|
34
|
-
|
35
26
|
def attributes=(attrs={})
|
36
27
|
attrs.each do |k, v|
|
37
28
|
self.send("#{k}=", v)
|
38
29
|
end
|
39
30
|
end
|
40
31
|
|
41
|
-
|
42
32
|
# email domain ... if a full email is provided, take just the domain portion
|
43
33
|
def domain=(email)
|
44
34
|
@domain = if email =~ /@(.+)/
|
@@ -51,16 +41,16 @@ module Maxmind
|
|
51
41
|
# customer email ... sends just an MD5 hash of the email.
|
52
42
|
# also sets the email domain at the same time.
|
53
43
|
def email=(email)
|
54
|
-
@email =
|
44
|
+
@email = md5_digest(email)
|
55
45
|
self.domain = email unless domain
|
56
46
|
end
|
57
47
|
|
58
48
|
def username=(username)
|
59
|
-
@username =
|
49
|
+
@username = md5_digest(username)
|
60
50
|
end
|
61
51
|
|
62
52
|
def password=(password)
|
63
|
-
@password =
|
53
|
+
@password = md5_digest(password)
|
64
54
|
end
|
65
55
|
|
66
56
|
# if a full card number is passed, grab just the first 6 digits (which is the bank id number)
|
@@ -68,10 +58,10 @@ module Maxmind
|
|
68
58
|
@bin = bin ? bin[0,6] : nil
|
69
59
|
end
|
70
60
|
|
71
|
-
|
72
61
|
def process!
|
73
62
|
resp = post(query)
|
74
|
-
|
63
|
+
resp.body.encode!("utf-8", "iso-8859-1") if resp.body.respond_to?(:encode!)
|
64
|
+
Maxmind::Response.new(resp.body, resp.code)
|
75
65
|
end
|
76
66
|
|
77
67
|
def process
|
@@ -80,9 +70,6 @@ module Maxmind
|
|
80
70
|
false
|
81
71
|
end
|
82
72
|
|
83
|
-
|
84
|
-
private
|
85
|
-
|
86
73
|
def query
|
87
74
|
validate
|
88
75
|
|
@@ -114,47 +101,58 @@ module Maxmind
|
|
114
101
|
:txnID => @transaction_id,
|
115
102
|
:sessionID => @session_id,
|
116
103
|
:user_agent => @user_agent,
|
117
|
-
:accept_language => @
|
104
|
+
:accept_language => @accept_language,
|
105
|
+
:avs_result => @avs_result,
|
106
|
+
:cvv_result => @cvv_result,
|
107
|
+
:txn_type => @txn_type,
|
108
|
+
:order_amount => @order_amount,
|
109
|
+
:order_currency => @order_currency
|
118
110
|
}
|
119
111
|
|
120
112
|
field_set = required_fields.merge(optional_fields)
|
121
113
|
field_set.reject {|k, v| v.nil? }
|
122
114
|
end
|
123
115
|
|
116
|
+
private
|
117
|
+
|
124
118
|
# Upon a failure at the first URL, will automatically retry with the
|
125
119
|
# second & third ones before finally raising an exception
|
120
|
+
# Returns an HTTPResponse object
|
126
121
|
def post(query_params)
|
127
122
|
servers ||= SERVERS.map{|hostname| "https://#{hostname}/app/ccv2r"}
|
128
123
|
url = URI.parse(servers.shift)
|
129
|
-
|
124
|
+
|
130
125
|
req = Net::HTTP::Post.new(url.path)
|
131
126
|
req.set_form_data(query_params)
|
132
127
|
|
133
128
|
h = Net::HTTP.new(url.host, url.port)
|
134
129
|
h.use_ssl = true
|
135
130
|
h.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
136
|
-
|
131
|
+
|
137
132
|
# set some timeouts
|
138
133
|
h.open_timeout = 60 # this blocks forever by default, lets be a bit less crazy.
|
139
134
|
h.read_timeout = self.class.timeout || DefaultTimeout
|
140
135
|
h.ssl_timeout = self.class.timeout || DefaultTimeout
|
141
136
|
|
142
|
-
|
143
|
-
response.body
|
137
|
+
h.start { |http| http.request(req) }
|
144
138
|
|
145
139
|
rescue Exception => e
|
146
140
|
retry if servers.size > 0
|
147
141
|
raise e
|
148
142
|
end
|
149
|
-
|
143
|
+
|
144
|
+
def md5_digest(value)
|
145
|
+
if value =~ /^[0-9a-f]{32}$/i
|
146
|
+
value
|
147
|
+
else
|
148
|
+
Digest::MD5.hexdigest(value.downcase)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
150
152
|
protected
|
151
153
|
def validate
|
152
154
|
raise ArgumentError, 'License key is required' unless Maxmind::license_key
|
153
155
|
raise ArgumentError, 'IP address is required' unless client_ip
|
154
|
-
raise ArgumentError, 'City is required' unless city
|
155
|
-
raise ArgumentError, 'Region is required' unless region
|
156
|
-
raise ArgumentError, 'Postal code is required' unless postal
|
157
|
-
raise ArgumentError, 'Country is required' unless country
|
158
156
|
end
|
159
157
|
end
|
160
158
|
end
|
data/lib/maxmind/response.rb
CHANGED
@@ -1,16 +1,20 @@
|
|
1
1
|
module Maxmind
|
2
2
|
class Response
|
3
3
|
attr_accessor :attributes
|
4
|
+
attr_reader :body, :http_code
|
4
5
|
|
5
6
|
ATTRIBUTE_MAP = {
|
6
7
|
'custPhoneInBillingLoc' => 'phone_in_billing_location',
|
7
8
|
'maxmindID' => 'maxmind_id',
|
8
9
|
'isTransProxy' => 'is_transparent_proxy',
|
9
|
-
'err' => 'error'
|
10
|
+
'err' => 'error',
|
11
|
+
'carderEmail' => 'high_risk_email'
|
10
12
|
}
|
11
13
|
|
12
|
-
def initialize(response = nil)
|
14
|
+
def initialize(response = nil, http_code = nil)
|
13
15
|
raise ArgumentError, 'Missing response string' unless response
|
16
|
+
@body = response
|
17
|
+
@http_code = http_code.to_i if http_code
|
14
18
|
@attributes = {}
|
15
19
|
parse(response)
|
16
20
|
end
|
@@ -34,8 +38,8 @@ module Maxmind
|
|
34
38
|
end
|
35
39
|
|
36
40
|
def method_missing(meth, *args)
|
37
|
-
if meth.to_s[-1] == '?'
|
38
|
-
send(meth[0..-2])
|
41
|
+
if meth.to_s[-1, 1] == '?'
|
42
|
+
send(meth.to_s[0..-2])
|
39
43
|
elsif attributes.has_key?(meth)
|
40
44
|
attributes[meth]
|
41
45
|
else
|
@@ -44,7 +48,7 @@ module Maxmind
|
|
44
48
|
end
|
45
49
|
|
46
50
|
def respond_to?(meth)
|
47
|
-
if meth.to_s[-1] == '?'
|
51
|
+
if meth.to_s[-1, 1] == '?'
|
48
52
|
respond_to? meth[0..-2]
|
49
53
|
else
|
50
54
|
super
|
@@ -64,13 +68,13 @@ module Maxmind
|
|
64
68
|
v = Integer(v) rescue Float(v) rescue v;
|
65
69
|
|
66
70
|
case v
|
67
|
-
when
|
71
|
+
when 'Yes', 'yes'
|
68
72
|
attributes[k] = true
|
69
|
-
when
|
73
|
+
when 'No', 'no'
|
70
74
|
attributes[k] = false
|
71
75
|
else
|
72
76
|
attributes[k] = v
|
73
77
|
end
|
74
78
|
end
|
75
79
|
end
|
76
|
-
end
|
80
|
+
end
|
data/lib/maxmind/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module Maxmind
|
2
|
-
VERSION = '0.4.
|
3
|
-
end
|
2
|
+
VERSION = '0.4.7'
|
3
|
+
end
|
data/lib/maxmind.rb
CHANGED
@@ -1,11 +1,18 @@
|
|
1
|
-
require 'active_support'
|
2
|
-
unless Module.respond_to?(:mattr_accessor)
|
3
|
-
require 'active_support/core_ext/module/attribute_accessors'# rescue nil # this may be needed for ActiveSupport versions >= 3.x
|
4
|
-
end
|
5
|
-
require 'active_support/core_ext/hash'
|
6
|
-
require 'net/http'
|
7
1
|
require 'net/https'
|
8
2
|
require 'uri'
|
9
3
|
require 'digest/md5'
|
10
|
-
|
11
|
-
require
|
4
|
+
|
5
|
+
require 'maxmind/version'
|
6
|
+
require 'maxmind/request'
|
7
|
+
require 'maxmind/chargeback_request'
|
8
|
+
require 'maxmind/chargeback_response'
|
9
|
+
require 'maxmind/response'
|
10
|
+
|
11
|
+
module Maxmind
|
12
|
+
SERVERS = %w(minfraud.maxmind.com minfraud-us-east.maxmind.com minfraud-us-west.maxmind.com)
|
13
|
+
|
14
|
+
class << self
|
15
|
+
attr_accessor :license_key
|
16
|
+
attr_accessor :user_id
|
17
|
+
end
|
18
|
+
end
|
data/maxmind.gemspec
CHANGED
@@ -3,28 +3,21 @@ $:.push File.expand_path('../lib', __FILE__)
|
|
3
3
|
require 'maxmind/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
|
-
s.name
|
7
|
-
s.version
|
6
|
+
s.name = "maxmind"
|
7
|
+
s.version = Maxmind::VERSION
|
8
8
|
|
9
|
-
s.authors
|
10
|
-
s.
|
11
|
-
s.
|
12
|
-
s.email = "adam@mediadrive.ca"
|
9
|
+
s.authors = ["Adam Daniels"]
|
10
|
+
s.description = "A wrapper around MaxMind's minFraud anti-fraud service. \n\nhttp://www.maxmind.com/app/ccv_overview\n"
|
11
|
+
s.email = "adam@mediadrive.ca"
|
13
12
|
s.extra_rdoc_files = [
|
14
13
|
"LICENSE",
|
15
14
|
"README.md"
|
16
15
|
]
|
17
|
-
|
18
|
-
s.files = `git ls-files`.split("\n")
|
19
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
-
s.homepage = "http://github.com/adam12/maxmind"
|
21
|
-
s.require_paths = ["lib"]
|
22
|
-
s.summary = "Wrapper for MaxMind's minFraud service"
|
23
16
|
|
24
|
-
s.
|
25
|
-
s.
|
26
|
-
s.
|
27
|
-
|
28
|
-
s.
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.homepage = "http://github.com/adam12/maxmind"
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
s.summary = "Wrapper for MaxMind's minFraud service"
|
22
|
+
s.license = 'MIT'
|
29
23
|
end
|
30
|
-
|
data/spec/data/response.txt
CHANGED
@@ -1 +1 @@
|
|
1
|
-
distance=329;countryMatch=Yes;countryCode=US;freeMail=Yes;anonymousProxy=No;score=7.66;binMatch=Yes;binCountry=US;err=;proxyScore=0.00;ip_region=NY;ip_city=Syracuse;ip_latitude=43.0514;ip_longitude=-76.1495;binName=;ip_isp=Road
|
1
|
+
distance=329;countryMatch=Yes;countryCode=US;freeMail=Yes;anonymousProxy=No;score=7.66;binMatch=Yes;binCountry=US;err=;proxyScore=0.00;ip_region=NY;ip_city=Syracuse;ip_latitude=43.0514;ip_longitude=-76.1495;binName=;ip_isp=Road Runnere�;ip_org=Road Runner;binNameMatch=Yes;binPhoneMatch=Yes;binPhone=;custPhoneInBillingLoc=No;highRiskCountry=No;queriesRemaining=955;cityPostalMatch=No;shipCityPostalMatch=Yes;maxmindID=9VSOSDE2;isTransProxy=No;carderEmail=Yes;shipForward=Yes;highRiskUsername=No;highRiskPassword=No;riskScore=2.00;explanation=This order is very high risk, and we suggest you not accept it. This order is considered to be very slightly higher risk because the distance between the billing address and the user's actual location is larger than expected. The order is slightly riskier because the e-mail domain, yahoo.com, is a free e-mail provider. The order is slightly riskier because the phone number supplied by the user is not located within the zip code of the billing address for the credit card. The order is riskier because the shipping address given is a mail forwarding address, so there is no way to know where the products are actually going
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Maxmind::ChargebackRequest do
|
4
|
+
before do
|
5
|
+
Maxmind.user_id = 'user'
|
6
|
+
Maxmind.license_key = 'key'
|
7
|
+
@request = Maxmind::ChargebackRequest.new(:client_ip => '198.51.100.2')
|
8
|
+
end
|
9
|
+
|
10
|
+
it "requires a License Key" do
|
11
|
+
Maxmind.license_key = nil
|
12
|
+
expect { @request.send(:validate) }.to raise_error(ArgumentError)
|
13
|
+
Maxmind.license_key = 'key'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "requires a User ID" do
|
17
|
+
Maxmind.user_id = nil
|
18
|
+
expect { @request.send(:validate) }.to raise_error(ArgumentError)
|
19
|
+
Maxmind.user_id = 'user'
|
20
|
+
end
|
21
|
+
|
22
|
+
it "requires a client IP" do
|
23
|
+
@request.client_ip = nil
|
24
|
+
expect { @request.send(:validate) }.to raise_error(ArgumentError)
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Maxmind::ChargebackResponse do
|
4
|
+
before do
|
5
|
+
Maxmind.user_id = 'USER_ID'
|
6
|
+
Maxmind.license_key = 'LICENSE_KEY'
|
7
|
+
|
8
|
+
request = Maxmind::ChargebackRequest.new(:client_ip => '198.51.100.2')
|
9
|
+
stub_request(:post, "https://USER_ID:LICENSE_KEY@minfraud.maxmind.com/minfraud/chargeback").
|
10
|
+
to_return(:body => '', :status => 200)
|
11
|
+
@response = request.process!
|
12
|
+
end
|
13
|
+
|
14
|
+
it "requires a response" do
|
15
|
+
expect { Maxmind::ChargebackResponse.new }.to raise_exception(ArgumentError)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "exposes the http response code" do
|
19
|
+
expect(@response.http_code).to eq 200
|
20
|
+
end
|
21
|
+
|
22
|
+
it "exposes the http response" do
|
23
|
+
expect(@response.response).to_not be_nil
|
24
|
+
end
|
25
|
+
end
|
@@ -14,37 +14,72 @@ describe Maxmind::Request do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
it "requires client IP" do
|
17
|
-
expect {
|
17
|
+
expect {
|
18
|
+
@request.client_ip = nil; @request.send(:validate)
|
19
|
+
}.to raise_exception(ArgumentError)
|
18
20
|
end
|
19
21
|
|
20
|
-
it "
|
21
|
-
expect {
|
22
|
+
it "doesn't require city" do
|
23
|
+
expect {
|
24
|
+
@request.city = nil; @request.send(:validate)
|
25
|
+
}.not_to raise_error
|
22
26
|
end
|
23
27
|
|
24
|
-
it "
|
25
|
-
expect {
|
28
|
+
it "doesn't require region" do
|
29
|
+
expect {
|
30
|
+
@request.region = nil; @request.send(:validate)
|
31
|
+
}.not_to raise_error
|
26
32
|
end
|
27
33
|
|
28
|
-
it "
|
29
|
-
expect {
|
34
|
+
it "doesn't require postal" do
|
35
|
+
expect {
|
36
|
+
@request.postal = nil; @request.send(:validate)
|
37
|
+
}.not_to raise_error
|
30
38
|
end
|
31
39
|
|
32
|
-
it "
|
33
|
-
expect {
|
40
|
+
it "doesn't require country" do
|
41
|
+
expect {
|
42
|
+
@request.country = nil; @request.send(:validate)
|
43
|
+
}.not_to raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
it "saves order currency" do
|
47
|
+
@request.order_currency = 'GBP'
|
48
|
+
expect(@request.query[:order_currency]).to eq 'GBP'
|
34
49
|
end
|
35
50
|
|
36
51
|
it "converts username to MD5" do
|
37
52
|
@request.username = 'testuser'
|
38
|
-
@request.username.
|
53
|
+
expect(@request.username).to eq '5d9c68c6c50ed3d02a2fcf54f63993b6'
|
39
54
|
end
|
40
55
|
|
41
56
|
it "converts password to MD5" do
|
42
57
|
@request.password = 'testpassword'
|
43
|
-
@request.password.
|
58
|
+
expect(@request.password).to eq 'e16b2ab8d12314bf4efbd6203906ea6c'
|
44
59
|
end
|
45
60
|
|
46
61
|
it "converts email to MD5" do
|
47
62
|
@request.email = 'test@test.com'
|
48
|
-
@request.email.
|
63
|
+
expect(@request.email).to eq 'b642b4217b34b1e8d3bd915fc65c4452'
|
64
|
+
end
|
65
|
+
|
66
|
+
it "does not double convert an md5 username" do
|
67
|
+
@request.username = 'b642b4217b34b1e8d3bd915fc65c4452'
|
68
|
+
expect(@request.username).to eq 'b642b4217b34b1e8d3bd915fc65c4452'
|
69
|
+
end
|
70
|
+
|
71
|
+
it "does not double convert an md5 password" do
|
72
|
+
@request.password = 'b642b4217b34b1e8d3bd915fc65c4452'
|
73
|
+
expect(@request.password).to eq 'b642b4217b34b1e8d3bd915fc65c4452'
|
49
74
|
end
|
50
|
-
|
75
|
+
|
76
|
+
it "does not double convert an md5 email" do
|
77
|
+
@request.email = 'b642b4217b34b1e8d3bd915fc65c4452'
|
78
|
+
expect(@request.email).to eq 'b642b4217b34b1e8d3bd915fc65c4452'
|
79
|
+
end
|
80
|
+
|
81
|
+
it "exposes the query parameters" do
|
82
|
+
expect(@request.query).to be_a Hash
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -1,11 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
REQUIRED_FIELDS =
|
4
|
-
|
5
|
-
RECOMMENDED_FIELDS =
|
6
|
-
|
7
|
-
OPTIONAL_FIELDS =
|
8
|
-
|
9
3
|
describe Maxmind::Response do
|
10
4
|
before do
|
11
5
|
Maxmind.license_key = 'LICENSE_KEY'
|
@@ -14,10 +8,12 @@ describe Maxmind::Response do
|
|
14
8
|
recommended_fields = JSON.parse(load_fixture("recommended_fields.json"))
|
15
9
|
optional_fields = JSON.parse(load_fixture("optional_fields.json"))
|
16
10
|
all_fields = required_fields.merge(recommended_fields).merge(optional_fields)
|
11
|
+
@response_body = load_fixture("response.txt")
|
12
|
+
@response_body.encode!("utf-8", "iso-8859-1") if @response_body.respond_to?(:encode!)
|
17
13
|
|
18
14
|
request = Maxmind::Request.new(all_fields)
|
19
15
|
stub_request(:post, "https://minfraud.maxmind.com/app/ccv2r").
|
20
|
-
to_return(:body =>
|
16
|
+
to_return(:body => @response_body, :status => 200)
|
21
17
|
@response = request.process!
|
22
18
|
end
|
23
19
|
|
@@ -26,47 +22,59 @@ describe Maxmind::Response do
|
|
26
22
|
end
|
27
23
|
|
28
24
|
it "exposes its attributes" do
|
29
|
-
@response.attributes.
|
25
|
+
expect(@response.attributes).to be_a Hash
|
26
|
+
end
|
27
|
+
|
28
|
+
it "exposes the raw response body" do
|
29
|
+
expect(@response.body).to eq @response_body
|
30
|
+
end
|
31
|
+
|
32
|
+
it "exposes the http response code" do
|
33
|
+
expect(@response.http_code).to eq 200
|
30
34
|
end
|
31
35
|
|
32
36
|
it "has a distance" do
|
33
|
-
@response.distance.
|
37
|
+
expect(@response.distance).to eq 329
|
34
38
|
end
|
35
39
|
|
36
40
|
it "has a maxmind ID" do
|
37
|
-
@response.maxmind_id.
|
41
|
+
expect(@response.maxmind_id).to eq '9VSOSDE2'
|
38
42
|
end
|
39
43
|
|
40
44
|
it "has a risk score" do
|
41
|
-
@response.risk_score.
|
45
|
+
expect(@response.risk_score).to eq 2.0
|
42
46
|
end
|
43
47
|
|
44
48
|
it "has a score" do
|
45
|
-
@response.score.
|
49
|
+
expect(@response.score).to eq 7.66
|
46
50
|
end
|
47
51
|
|
48
52
|
it "has queries remaining" do
|
49
|
-
@response.queries_remaining.
|
53
|
+
expect(@response.queries_remaining).to eq 955
|
50
54
|
end
|
51
55
|
|
52
56
|
it "has an explanation" do
|
53
|
-
@response.explanation.
|
57
|
+
expect(@response.explanation).to be_a String
|
54
58
|
end
|
55
59
|
|
56
60
|
it "has a country match" do
|
57
|
-
@response.country_match.
|
61
|
+
expect(@response.country_match).not_to be_nil
|
58
62
|
end
|
59
63
|
|
60
64
|
it "has a boolean country match" do
|
61
|
-
@response.country_match.
|
62
|
-
@response.country_match.
|
65
|
+
expect(@response.country_match).not_to eq "Yes"
|
66
|
+
expect(@response.country_match).to be_truthy
|
63
67
|
end
|
64
68
|
|
65
69
|
it "has a phone in billing location" do
|
66
|
-
@response.phone_in_billing_location.
|
70
|
+
expect(@response.phone_in_billing_location).to be_falsey
|
67
71
|
end
|
68
72
|
|
69
73
|
it "has a phone in billing location ? method" do
|
70
|
-
@response.phone_in_billing_location
|
74
|
+
expect(@response.phone_in_billing_location?).to be_falsey
|
75
|
+
end
|
76
|
+
|
77
|
+
it "has a high risk email" do
|
78
|
+
expect(@response.high_risk_email).to be_truthy
|
71
79
|
end
|
72
|
-
end
|
80
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
require '
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
require 'mocha/api'
|
2
5
|
require 'maxmind'
|
3
6
|
require 'json'
|
4
7
|
require 'webmock/rspec'
|
@@ -7,24 +10,12 @@ RSpec.configure do |config|
|
|
7
10
|
|
8
11
|
config.before(:suite) do
|
9
12
|
# Disable all live HTTP requests
|
10
|
-
WebMock.disable_net_connect!(allow_localhost
|
13
|
+
WebMock.disable_net_connect!(:allow_localhost => true)
|
11
14
|
end
|
12
15
|
|
13
16
|
config.mock_with :mocha
|
14
17
|
end
|
15
18
|
|
16
|
-
# Constants (classes, etc) defined within a block passed to this method
|
17
|
-
# will be removed from the global namespace after the block as run.
|
18
|
-
def isolate_constants
|
19
|
-
existing_constants = Object.constants
|
20
|
-
yield
|
21
|
-
ensure
|
22
|
-
(Object.constants - existing_constants).each do |constant|
|
23
|
-
Object.send(:remove_const, constant)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
19
|
def load_fixture(*filename)
|
29
20
|
File.open(File.join('spec', 'data', *filename)).read
|
30
21
|
end
|
metadata
CHANGED
@@ -1,84 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: maxmind
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
5
|
-
prerelease:
|
4
|
+
version: 0.4.7
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Adam Daniels
|
9
|
-
- Tinu Cleatus
|
10
|
-
- t.e.morgan
|
11
|
-
- Sam Oliver
|
12
8
|
autorequire:
|
13
9
|
bindir: bin
|
14
10
|
cert_chain: []
|
15
|
-
date:
|
16
|
-
dependencies:
|
17
|
-
-
|
18
|
-
name: rspec
|
19
|
-
requirement: !ruby/object:Gem::Requirement
|
20
|
-
none: false
|
21
|
-
requirements:
|
22
|
-
- - ! '>='
|
23
|
-
- !ruby/object:Gem::Version
|
24
|
-
version: '0'
|
25
|
-
type: :development
|
26
|
-
prerelease: false
|
27
|
-
version_requirements: !ruby/object:Gem::Requirement
|
28
|
-
none: false
|
29
|
-
requirements:
|
30
|
-
- - ! '>='
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '0'
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: mocha
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
36
|
-
none: false
|
37
|
-
requirements:
|
38
|
-
- - ! '>='
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
type: :development
|
42
|
-
prerelease: false
|
43
|
-
version_requirements: !ruby/object:Gem::Requirement
|
44
|
-
none: false
|
45
|
-
requirements:
|
46
|
-
- - ! '>='
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version: '0'
|
49
|
-
- !ruby/object:Gem::Dependency
|
50
|
-
name: webmock
|
51
|
-
requirement: !ruby/object:Gem::Requirement
|
52
|
-
none: false
|
53
|
-
requirements:
|
54
|
-
- - ! '>='
|
55
|
-
- !ruby/object:Gem::Version
|
56
|
-
version: '0'
|
57
|
-
type: :development
|
58
|
-
prerelease: false
|
59
|
-
version_requirements: !ruby/object:Gem::Requirement
|
60
|
-
none: false
|
61
|
-
requirements:
|
62
|
-
- - ! '>='
|
63
|
-
- !ruby/object:Gem::Version
|
64
|
-
version: '0'
|
65
|
-
- !ruby/object:Gem::Dependency
|
66
|
-
name: active_support
|
67
|
-
requirement: !ruby/object:Gem::Requirement
|
68
|
-
none: false
|
69
|
-
requirements:
|
70
|
-
- - ! '>='
|
71
|
-
- !ruby/object:Gem::Version
|
72
|
-
version: 3.0.0
|
73
|
-
type: :runtime
|
74
|
-
prerelease: false
|
75
|
-
version_requirements: !ruby/object:Gem::Requirement
|
76
|
-
none: false
|
77
|
-
requirements:
|
78
|
-
- - ! '>='
|
79
|
-
- !ruby/object:Gem::Version
|
80
|
-
version: 3.0.0
|
81
|
-
description: ! "A wrapper around MaxMind's minFraud anti-fraud service. \n\nhttp://www.maxmind.com/app/ccv_overview\n"
|
11
|
+
date: 2015-10-22 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: "A wrapper around MaxMind's minFraud anti-fraud service. \n\nhttp://www.maxmind.com/app/ccv_overview\n"
|
82
14
|
email: adam@mediadrive.ca
|
83
15
|
executables: []
|
84
16
|
extensions: []
|
@@ -86,14 +18,18 @@ extra_rdoc_files:
|
|
86
18
|
- LICENSE
|
87
19
|
- README.md
|
88
20
|
files:
|
89
|
-
- .gitignore
|
21
|
+
- ".gitignore"
|
22
|
+
- ".travis.yml"
|
90
23
|
- Gemfile
|
91
24
|
- Guardfile
|
92
25
|
- LICENSE
|
93
26
|
- README.md
|
94
27
|
- Rakefile
|
28
|
+
- examples/chargeback_example.rb
|
95
29
|
- examples/example.rb
|
96
30
|
- lib/maxmind.rb
|
31
|
+
- lib/maxmind/chargeback_request.rb
|
32
|
+
- lib/maxmind/chargeback_response.rb
|
97
33
|
- lib/maxmind/request.rb
|
98
34
|
- lib/maxmind/response.rb
|
99
35
|
- lib/maxmind/version.rb
|
@@ -102,44 +38,42 @@ files:
|
|
102
38
|
- spec/data/recommended_fields.json
|
103
39
|
- spec/data/required_fields.json
|
104
40
|
- spec/data/response.txt
|
41
|
+
- spec/maxmind/chargeback_request_spec.rb
|
42
|
+
- spec/maxmind/chargeback_response_spec.rb
|
105
43
|
- spec/maxmind/request_spec.rb
|
106
44
|
- spec/maxmind/response_spec.rb
|
107
45
|
- spec/spec_helper.rb
|
108
46
|
homepage: http://github.com/adam12/maxmind
|
109
|
-
licenses:
|
47
|
+
licenses:
|
48
|
+
- MIT
|
49
|
+
metadata: {}
|
110
50
|
post_install_message:
|
111
51
|
rdoc_options: []
|
112
52
|
require_paths:
|
113
53
|
- lib
|
114
54
|
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
-
none: false
|
116
55
|
requirements:
|
117
|
-
- -
|
56
|
+
- - ">="
|
118
57
|
- !ruby/object:Gem::Version
|
119
58
|
version: '0'
|
120
|
-
segments:
|
121
|
-
- 0
|
122
|
-
hash: -1867686245011996081
|
123
59
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
|
-
none: false
|
125
60
|
requirements:
|
126
|
-
- -
|
61
|
+
- - ">="
|
127
62
|
- !ruby/object:Gem::Version
|
128
63
|
version: '0'
|
129
|
-
segments:
|
130
|
-
- 0
|
131
|
-
hash: -1867686245011996081
|
132
64
|
requirements: []
|
133
65
|
rubyforge_project:
|
134
|
-
rubygems_version:
|
66
|
+
rubygems_version: 2.4.8
|
135
67
|
signing_key:
|
136
|
-
specification_version:
|
68
|
+
specification_version: 4
|
137
69
|
summary: Wrapper for MaxMind's minFraud service
|
138
70
|
test_files:
|
139
71
|
- spec/data/optional_fields.json
|
140
72
|
- spec/data/recommended_fields.json
|
141
73
|
- spec/data/required_fields.json
|
142
74
|
- spec/data/response.txt
|
75
|
+
- spec/maxmind/chargeback_request_spec.rb
|
76
|
+
- spec/maxmind/chargeback_response_spec.rb
|
143
77
|
- spec/maxmind/request_spec.rb
|
144
78
|
- spec/maxmind/response_spec.rb
|
145
79
|
- spec/spec_helper.rb
|