/
request.rb
170 lines (138 loc) · 4.79 KB
/
request.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
module Maxmind
# Your license key
class << self
attr_accessor :license_key
end
SERVERS = %w(minfraud.maxmind.com minfraud-us-east.maxmind.com minfraud-us-west.maxmind.com)
class Request
DefaultTimeout = 60
# optionally set a default request type (one of 'standard' or 'premium')
# Maxmind's default behavior is to use premium if you have credits, else use standard
class << self
attr_accessor :default_request_type
attr_accessor :timeout
end
# Required Fields
attr_accessor :client_ip, :city, :region, :postal, :country
# Optional Fields
attr_accessor :domain, :bin, :bin_name, :bin_phone, :cust_phone, :request_type,
:forwarded_ip, :email, :username, :password, :transaction_id, :session_id,
:shipping_address, :shipping_city, :shipping_region, :shipping_postal,
:shipping_country, :user_agent, :accept_language, :order_amount,
:order_currency, :avs_result, :cvv_result
def initialize(attrs={})
self.attributes = attrs
end
def attributes=(attrs={})
attrs.each do |k, v|
self.send("#{k}=", v)
end
end
# email domain ... if a full email is provided, take just the domain portion
def domain=(email)
@domain = if email =~ /@(.+)/
$1
else
email
end
end
# customer email ... sends just an MD5 hash of the email.
# also sets the email domain at the same time.
def email=(email)
@email = md5_digest(email)
self.domain = email unless domain
end
def username=(username)
@username = md5_digest(username)
end
def password=(password)
@password = md5_digest(password)
end
# if a full card number is passed, grab just the first 6 digits (which is the bank id number)
def bin=(bin)
@bin = bin ? bin[0,6] : nil
end
def process!
resp = post(query)
Maxmind::Response.new(resp)
end
def process
process!
rescue Exception => e
false
end
private
def query
validate
required_fields = {
:i => @client_ip,
:city => @city,
:region => @region,
:postal => @postal,
:country => @country,
:license_key => Maxmind::license_key
}
optional_fields = {
:domain => @domain,
:bin => @bin,
:binName => @bin_name,
:binPhone => @bin_phone,
:custPhone => @cust_phone,
:requested_type => @request_type || self.class.default_request_type,
:forwardedIP => @forwarded_ip,
:emailMD5 => @email,
:usernameMD5 => @username,
:passwordMD5 => @password,
:shipAddr => @shipping_address,
:shipCity => @shipping_city,
:shipRegion => @shipping_region,
:shipPostal => @shipping_postal,
:shipCountry => @shipping_country,
:txnID => @transaction_id,
:sessionID => @session_id,
:user_agent => @user_agent,
:accept_language => @accept_langage,
:avs_result => @avs_result,
:cvv_result => @cvv_result
}
field_set = required_fields.merge(optional_fields)
field_set.reject {|k, v| v.nil? }
end
# Upon a failure at the first URL, will automatically retry with the
# second & third ones before finally raising an exception
def post(query_params)
servers ||= SERVERS.map{|hostname| "https://#{hostname}/app/ccv2r"}
url = URI.parse(servers.shift)
req = Net::HTTP::Post.new(url.path)
req.set_form_data(query_params)
h = Net::HTTP.new(url.host, url.port)
h.use_ssl = true
h.verify_mode = OpenSSL::SSL::VERIFY_NONE
# set some timeouts
h.open_timeout = 60 # this blocks forever by default, lets be a bit less crazy.
h.read_timeout = self.class.timeout || DefaultTimeout
h.ssl_timeout = self.class.timeout || DefaultTimeout
response = h.start { |http| http.request(req) }
response.body
rescue Exception => e
retry if servers.size > 0
raise e
end
def md5_digest(value)
if value =~ /^[0-9a-f]{32}$/i
value
else
Digest::MD5.hexdigest(value.downcase)
end
end
protected
def validate
raise ArgumentError, 'License key is required' unless Maxmind::license_key
raise ArgumentError, 'IP address is required' unless client_ip
raise ArgumentError, 'City is required' unless city
raise ArgumentError, 'Region is required' unless region
raise ArgumentError, 'Postal code is required' unless postal
raise ArgumentError, 'Country is required' unless country
end
end
end