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 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
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - '1.9.3'
4
+ - '2.1.3'
5
+ - '2.2.0'
data/Gemfile CHANGED
@@ -1,2 +1,9 @@
1
- source :rubygems
2
- gemspec
1
+ source 'http://rubygems.org'
2
+ gemspec
3
+
4
+ gem 'guard-rspec'
5
+ gem 'rake'
6
+ gem 'rdoc'
7
+ gem 'rspec'
8
+ gem 'mocha'
9
+ gem 'webmock'
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
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 Adam
1
+ Copyright (c) 2009 Adam Daniels
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  maxmind
2
2
  ==========
3
3
 
4
- A wrapper around MaxMind's minFraud anti-fraud service.
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 test
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
@@ -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 = Digest::MD5.hexdigest(email.downcase)
44
+ @email = md5_digest(email)
55
45
  self.domain = email unless domain
56
46
  end
57
47
 
58
48
  def username=(username)
59
- @username = Digest::MD5.hexdigest(username.downcase)
49
+ @username = md5_digest(username)
60
50
  end
61
51
 
62
52
  def password=(password)
63
- @password = Digest::MD5.hexdigest(password.downcase)
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
- Maxmind::Response.new(resp)
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 => @accept_langage
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
- response = h.start { |http| http.request(req) }
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
@@ -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 /[Yy]es/
71
+ when 'Yes', 'yes'
68
72
  attributes[k] = true
69
- when /[Nn]o/
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
@@ -1,3 +1,3 @@
1
1
  module Maxmind
2
- VERSION = '0.4.2'
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
- require File.join(File.dirname(__FILE__), 'maxmind/request')
11
- require File.join(File.dirname(__FILE__), 'maxmind/response')
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 = "maxmind"
7
- s.version = Maxmind::VERSION
6
+ s.name = "maxmind"
7
+ s.version = Maxmind::VERSION
8
8
 
9
- s.authors = ["Adam Daniels", "Tinu Cleatus", "t.e.morgan", "Sam Oliver"]
10
- s.date = "2012-01-06"
11
- s.description = "A wrapper around MaxMind's minFraud anti-fraud service. \n\nhttp://www.maxmind.com/app/ccv_overview\n"
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.add_development_dependency 'rspec'
25
- s.add_development_dependency 'mocha'
26
- s.add_development_dependency 'webmock'
27
-
28
- s.add_runtime_dependency 'active_support', '>= 3.0.0'
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
-
@@ -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 Runner;ip_org=Road Runner;binNameMatch=Yes;binPhoneMatch=Yes;binPhone=;custPhoneInBillingLoc=No;highRiskCountry=No;queriesRemaining=955;cityPostalMatch=No;shipCityPostalMatch=Yes;maxmindID=9VSOSDE2;isTransProxy=No;carderEmail=No;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
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 { @request.client_ip = nil; @request.send(:validate) }.to raise_exception(ArgumentError)
17
+ expect {
18
+ @request.client_ip = nil; @request.send(:validate)
19
+ }.to raise_exception(ArgumentError)
18
20
  end
19
21
 
20
- it "requires city" do
21
- expect { @request.city = nil; @request.send(:validate) }.to raise_exception(ArgumentError)
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 "requires region" do
25
- expect { @request.region = nil; @request.send(:validate) }.to raise_exception(ArgumentError)
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 "requires postal" do
29
- expect { @request.postal = nil; @request.send(:validate) }.to raise_exception(ArgumentError)
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 "requires country" do
33
- expect { @request.country = nil; @request.send(:validate) }.to raise_exception(ArgumentError)
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.should == '5d9c68c6c50ed3d02a2fcf54f63993b6'
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.should == 'e16b2ab8d12314bf4efbd6203906ea6c'
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.should == 'b642b4217b34b1e8d3bd915fc65c4452'
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
- end
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 => load_fixture("response.txt"), :status => 200)
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.should be_a Hash
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.should == 329
37
+ expect(@response.distance).to eq 329
34
38
  end
35
39
 
36
40
  it "has a maxmind ID" do
37
- @response.maxmind_id.should == '9VSOSDE2'
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.should == 2.0
45
+ expect(@response.risk_score).to eq 2.0
42
46
  end
43
47
 
44
48
  it "has a score" do
45
- @response.score.should == 7.66
49
+ expect(@response.score).to eq 7.66
46
50
  end
47
51
 
48
52
  it "has queries remaining" do
49
- @response.queries_remaining.should == 955
53
+ expect(@response.queries_remaining).to eq 955
50
54
  end
51
55
 
52
56
  it "has an explanation" do
53
- @response.explanation.should_not == nil
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.should_not == nil
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.should_not == "Yes"
62
- @response.country_match.should == true
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.should == false
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?.should == false
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 'mocha_standalone'
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: true)
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.2
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: 2012-01-06 00:00:00.000000000 Z
16
- dependencies:
17
- - !ruby/object:Gem::Dependency
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: 1.8.21
66
+ rubygems_version: 2.4.8
135
67
  signing_key:
136
- specification_version: 3
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