maxminder 1.0.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.
@@ -0,0 +1,36 @@
1
+ require 'uri'
2
+ require 'net/https'
3
+ require 'logger'
4
+ require 'timeout'
5
+
6
+ require 'max_mind/enquiry'
7
+ require 'max_mind/lookup'
8
+
9
+ module MaxMind
10
+
11
+ ## Exception class for generic errors.
12
+ class Error < StandardError; end
13
+
14
+ ## Exception class for when connection to the max mind service fails.
15
+ class ConnectionError < Error; end
16
+
17
+ class << self
18
+ ## Licence key for accessing the maxmind service. A trial key
19
+ ## can be requested from http://www.maxmind.com/app/ccv2r_signup
20
+ attr_accessor :licence_key
21
+
22
+ ## The server (or servers) to accept your request
23
+ attr_accessor :endpoints
24
+
25
+ ## Return a default array of end points if none are specified.
26
+ def endpoints
27
+ @endpoints || ["https://minfraud1.maxmind.com/app/ccv2r", "https://minfraud3.maxmind.com/app/ccv2r"]
28
+ end
29
+
30
+ ## Return a logger object for this MaxMind interaction
31
+ def logger
32
+ @logger ||= Logger.new(STDOUT)
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,120 @@
1
+ module MaxMind
2
+ class Enquiry
3
+
4
+ attr_accessor :attributes
5
+
6
+ def initialize(attributes = {})
7
+ self.attributes = attributes if attributes.is_a?(Hash)
8
+ end
9
+
10
+ ## The attributes here will be sent to max mind
11
+ def sendable_attributes
12
+ hash = Hash.new
13
+ for field, data in attributes
14
+ hash[mapping[field]] = data
15
+ end
16
+ hash['license_key'] = MaxMind.licence_key
17
+ hash
18
+ end
19
+
20
+ ## Run the check and return a hash of responses from the server.
21
+ def lookup
22
+ MaxMind.logger.debug "Beginning lookups"
23
+ MaxMind.logger.debug "('#{sendable_attributes.inspect}')"
24
+ for endpoint in MaxMind.endpoints
25
+ MaxMind.logger.debug "Attempting lookup on #{endpoint}"
26
+ uri = URI.parse(endpoint)
27
+ req = Net::HTTP::Post.new(uri.path)
28
+ req.set_form_data(sendable_attributes)
29
+ res = Net::HTTP.new(uri.host, uri.port)
30
+ if uri.scheme == 'https'
31
+ res.use_ssl = true
32
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
33
+ end
34
+
35
+ begin
36
+ case res = res.request(req)
37
+ when Net::HTTPSuccess
38
+ return Lookup.new(res.body)
39
+ else
40
+ MaxMind.logger.debug "Error on #{endpoint} (#{res.class.to_s})"
41
+ next
42
+ end
43
+ rescue Timeout::Error
44
+ MaxMind.logger.debug "Timed out connecting to #{endpoint}"
45
+ next
46
+ end
47
+ end
48
+
49
+ false
50
+ end
51
+
52
+ ## Set or get an attribute from the attributes hash or raise
53
+ ## no method error if it doesn't exist in our mapping.
54
+ def method_missing(name, value = nil)
55
+ attribute_name = name.to_s.gsub(/\=\z/, '').to_sym
56
+ return super unless mapping.keys.include?(attribute_name)
57
+ value ? (attributes[attribute_name] = value) : attributes[attribute_name]
58
+ end
59
+
60
+ ## Various methods to make setting fields in the attributes hash
61
+ ## a little easier.
62
+ attr_reader :email, :username, :password
63
+
64
+ def email=(value)
65
+ @email = value
66
+ self.attributes[:email_md5] = Digest::MD5.hexdigest(value)
67
+ self.attributes[:email_domain] = value.split('@', 2).last
68
+ value
69
+ end
70
+
71
+ def username=(value)
72
+ @username = value
73
+ self.attributes[:username_md5] = Digest::MD5.hexdigest(value)
74
+ value
75
+ end
76
+
77
+ def password=(value)
78
+ @password = value
79
+ self.attributes[:password_md5] = Digest::MD5.hexdigest(value)
80
+ value
81
+ end
82
+
83
+ private
84
+
85
+ ## This method returns a mapping of method names to the appropriate attribute
86
+ ## expected by the MaxMind API.
87
+ def mapping
88
+ {
89
+ :ip_address => 'i',
90
+ :forwarded_ip => 'forwardedIP',
91
+
92
+ :city => 'city',
93
+ :region => 'region',
94
+ :postal => 'postal',
95
+ :country => 'country',
96
+
97
+ :shipping_address => 'shipAddr',
98
+ :shipping_city => 'shipCity',
99
+ :shipping_region => 'shipRegion',
100
+ :shipping_postal => 'shipPostal',
101
+ :shipping_country => 'shipCountry',
102
+
103
+ :email_domain => 'domain',
104
+ :email_md5 => 'emailMD5',
105
+ :username_md5 => 'usernameMD5',
106
+ :password_md5 => 'passwordMD5',
107
+
108
+ :bin => 'bin',
109
+ :bin_name => 'binName',
110
+ :bin_phone => 'binPhone',
111
+
112
+ :transaction_id => 'txnID',
113
+ :session_id => 'sessionID',
114
+ :user_agent => 'user_agent',
115
+ :accept_language => 'accept_language'
116
+ }
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,78 @@
1
+ module MaxMind
2
+ class Lookup
3
+
4
+ def initialize(raw)
5
+ @attributes = Hash.new
6
+ for key, value in raw.split(';').map{|r| r.split('=', 2)}
7
+ field_name, type = mapping[key]
8
+ @attributes[field_name] = parse_value(value, type)
9
+ end
10
+ end
11
+
12
+ ## Return the appropriate attribute from the attributes hash.
13
+ def method_missing(name)
14
+ super unless mapping.values.map(&:first).include?(name.to_sym)
15
+ @attributes[name.to_sym]
16
+ end
17
+
18
+ private
19
+
20
+ ## This is the mapping of response attributes to their local variable name
21
+ ## and type of data which is expected.
22
+ def mapping
23
+ {
24
+ 'countryMatch' => [:country_match, :boolean],
25
+ 'countryCode' => [:country_code, :string],
26
+ 'highRiskCountry' => [:high_risk_country?, :boolean],
27
+ 'distance' => [:distance, :integer],
28
+ 'ip_region' => [:ip_region, :string],
29
+ 'ip_city' => [:ip_city, :string],
30
+ 'ip_latitude' => [:ip_latitude, :decimal],
31
+ 'ip_longitude' => [:ip_longitude, :decimal],
32
+ 'ip_isp' => [:ip_isp, :string],
33
+ 'ip_org' => [:ip_organisation, :string],
34
+ 'anonymousProxy' => [:anonymous_proxy?, :boolean],
35
+ 'proxyScore' => [:proxy_score, :float],
36
+ 'isTransProxy' => [:transparent_proxy?, :boolean],
37
+ 'freeMail' => [:free_email?, :boolean],
38
+ 'carderEmail' => [:high_risk_email?, :boolean],
39
+ 'highRiskUsername' => [:high_risk_username?, :boolean],
40
+ 'highRiskPassword' => [:high_risk_password?, :boolean],
41
+ 'binMatch' => [:bin_match?, :boolean],
42
+ 'binCountry' => [:bin_country, :string],
43
+ 'binNameMatch' => [:bin_name_match?, :boolean],
44
+ 'binName' => [:bin_name, :string],
45
+ 'binPhoneMatch' => [:bin_phone_match?, :boolean],
46
+ 'binPhone' => [:bin_phone, :string],
47
+ 'custPhoneInBillingLoc' => [:phone_in_billing_location?, :boolean],
48
+ 'shipForward' => [:mail_drop_address?, :boolean],
49
+ 'cityPostalMatch' => [:city_matches_postal?, :boolean],
50
+ 'shipCityPostalMatch' => [:ship_city_matches_postal?, :boolean],
51
+ 'score' => [:score, :decimal],
52
+ 'explanation' => [:explanation, :string],
53
+ 'riskScore' => [:risk_score, :decimal],
54
+ 'queriesRemaining' => [:queries_remaining, :decimal],
55
+ 'maxmindID' => [:id, :string],
56
+ 'err' => [:error, :string]
57
+ }
58
+ end
59
+
60
+ ## Return a value as an instance of an appropriate ruby object.
61
+ def parse_value(value, type = :string)
62
+ case type
63
+ when :integer then value.to_i
64
+ when :decimal then value.to_f
65
+ when :boolean
66
+ case value
67
+ when 'Yes' then true
68
+ when 'No' then false
69
+ else
70
+ nil
71
+ end
72
+ else
73
+ value
74
+ end
75
+ end
76
+
77
+ end
78
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: maxminder
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Adam Cooke
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-09-05 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description:
22
+ email: adam@atechmedia.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - lib/max_mind/enquiry.rb
31
+ - lib/max_mind/lookup.rb
32
+ - lib/max_mind.rb
33
+ has_rdoc: false
34
+ homepage: http://github.com/adamcooke/maxminder
35
+ licenses: []
36
+
37
+ post_install_message:
38
+ rdoc_options: []
39
+
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ requirements: []
57
+
58
+ rubyforge_project:
59
+ rubygems_version: 1.3.6
60
+ signing_key:
61
+ specification_version: 3
62
+ summary: Simple (non-bloated) Ruby library for MaxMind
63
+ test_files: []
64
+