hamburglar 0.1.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,14 @@
1
+ module Hamburglar
2
+ class Config
3
+ attr_accessor :gateway
4
+ attr_accessor :credentials
5
+ attr_accessor :fraud_score
6
+ attr_accessor :fraud_proc
7
+
8
+ def initialize
9
+ @gateway = :min_fraud
10
+ @credentials = {}
11
+ @fraud_score = 2.5
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,26 @@
1
+ module Hamburglar
2
+ # Raised when trying to assign an invalid gateway to Hamburglar.gateway
3
+ class InvalidGateway < StandardError
4
+ def initialize(gateway = nil)
5
+ msg = "Invalid gateway"
6
+ msg << ", #{gateway}" if gateway
7
+ super msg
8
+ end
9
+ end
10
+
11
+ # Raised when trying to assign an invalid gateway URL
12
+ class InvalidURL < StandardError
13
+ def initialize(url = nil)
14
+ msg = "Invalid url"
15
+ msg << ", #{url}" if url
16
+ super msg
17
+ end
18
+ end
19
+
20
+ # Raised if Hamburglar::Gateways::Base.validate! fails
21
+ class InvalidRequest < StandardError
22
+ def initialize(msg = nil)
23
+ super "Invalid request"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,152 @@
1
+ require 'net/https'
2
+ require 'cgi'
3
+
4
+ module Hamburglar
5
+ module Gateways
6
+ # Hamburglar::Gateways::Base is the main class that handles sending API
7
+ # requests to upstream providers. All other gateways should inherit from
8
+ # this class
9
+ class Base
10
+
11
+ URL_REGEX = /https?:\/\/[\S]+/
12
+
13
+ # The parameters for the API request
14
+ attr_reader :params
15
+
16
+ # Errors returned when validating or submitting a request
17
+ attr_reader :errors
18
+
19
+ # Response returned by an API call
20
+ attr_reader :response
21
+
22
+ class << self
23
+ # The API URL
24
+ attr_reader :api_url
25
+ end
26
+
27
+ def initialize(params = {})
28
+ defaults = (Hamburglar.config.credentials || {}).select do |key, val|
29
+ optional_params.include? key
30
+ end
31
+ @params = Hash[defaults].merge(params)
32
+ @errors = {}
33
+ @response = {}
34
+ end
35
+
36
+ # Get or set the API URL for the gateway
37
+ def self.set_api_url(url = '')
38
+ if url.match URL_REGEX
39
+ @api_url = url
40
+ else
41
+ raise Hamburglar::InvalidURL, url
42
+ end
43
+ end
44
+
45
+ # Set required parameters for an API call
46
+ def self.set_required_params(*params)
47
+ @required_params = params
48
+ end
49
+
50
+ # Required parameters for an API call
51
+ def self.required_params
52
+ @required_params || []
53
+ end
54
+
55
+ # Validate presence of required_params
56
+ #
57
+ # Returns false if a parameter isn't set
58
+ def validate(revalidate = false)
59
+ @validated = false if revalidate
60
+ unless @validated
61
+ @errors[:missing_parameters] = []
62
+ self.class.required_params.each do |req|
63
+ unless @params.has_key?(req)
64
+ @errors[:missing_parameters] << req
65
+ end
66
+ end
67
+ @validated = true
68
+ end
69
+ @errors[:missing_parameters].empty?
70
+ end
71
+ alias_method :valid?, :validate
72
+
73
+ # Validate presence of required_params
74
+ #
75
+ # Raises Hamburglar::InvalidRequest if validation fails
76
+ def validate!
77
+ validate || raise(Hamburglar::InvalidRequest)
78
+ end
79
+
80
+ # Submit a request upstream to generate a fraud report
81
+ def submit
82
+ return false unless valid?
83
+ url = "#{self.class.api_url}?#{query_string}"
84
+ if res = fetch(url)
85
+ @response = parse_response(res.body)
86
+ end
87
+ end
88
+
89
+ # Optional parameters that *may* be present in a query
90
+ #
91
+ # This method should be overridden by classes than inherit from
92
+ # Hamburglar::Gateways::Base
93
+ #
94
+ # Defaults to self.required_params
95
+ def optional_params
96
+ self.class.required_params
97
+ end
98
+
99
+ private
100
+
101
+ # Formats @params into a query string for an HTTP GET request
102
+ def query_string
103
+ @params.map { |key, val| "#{key}=#{CGI.escape(val.to_s)}" }.join('&')
104
+ end
105
+
106
+ # Parses raw data returned from an API call
107
+ #
108
+ # This method should be overwritten by any API subclasses that
109
+ # return data in a different format
110
+ #
111
+ # Returns [Hash]
112
+ def parse_response(raw = '')
113
+ data = raw.to_s.split(';').map do |line|
114
+ key, val = line.split('=')
115
+ if key.to_s != "" && val.to_s != ""
116
+ [key.to_sym, val]
117
+ else
118
+ next
119
+ end
120
+ end
121
+ Hash[data]
122
+ end
123
+
124
+ # Performs a GET request on the given URI, redirects if needed
125
+ #
126
+ # See Following Redirection at
127
+ # http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/classes/Net/HTTP.html
128
+ def fetch(uri_str, limit = 10)
129
+ # You should choose better exception.
130
+ raise ArgumentError, 'HTTP redirect too deep' if limit == 0
131
+
132
+ uri = URI.parse(uri_str)
133
+ http = Net::HTTP.new(uri.host, uri.port)
134
+ if uri.scheme == 'https'
135
+ http.use_ssl = true
136
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
137
+ http.ca_file = File.expand_path('../../../cacert.pem', __FILE__)
138
+ end
139
+ request = Net::HTTP::Get.new(uri.request_uri)
140
+ response = http.start { |http| http.request(request) }
141
+
142
+ case response
143
+ when Net::HTTPSuccess then response
144
+ when Net::HTTPRedirection then fetch(response['location'], limit - 1)
145
+ else
146
+ response.error!
147
+ end
148
+ end
149
+
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,68 @@
1
+ module Hamburglar
2
+ module Gateways
3
+ # The MaxMind module contains classes for working
4
+ # with MaxMind's minFraud and Telephone Verification APIs
5
+ module MaxMind
6
+ # The MinFraud class handles fraud verification
7
+ # through MaxMind's minFraud API.
8
+ #
9
+ # See: http://www.maxmind.com/app/ccv
10
+ class MinFraud < Base
11
+ # The MaxMind API URL
12
+ set_api_url "https://minfraud2.maxmind.com/app/ccv2r"
13
+
14
+ # Required parameters for a minFraud API call
15
+ set_required_params :i, :city, :region, :postal, :country, :license_key
16
+
17
+ # Optional parameters
18
+ def optional_params
19
+ [
20
+ :i,
21
+ :city,
22
+ :region,
23
+ :postal,
24
+ :country,
25
+ :license_key,
26
+ :domain,
27
+ :bin,
28
+ :binName,
29
+ :binPhone,
30
+ :custPhone,
31
+ :requested_type,
32
+ :forwardedIP,
33
+ :emailMD5,
34
+ :usernameMD5,
35
+ :passwordMD5,
36
+ :shipAddr,
37
+ :shipCity,
38
+ :shipRegion,
39
+ :shipPostal,
40
+ :shipCountry,
41
+ :textID,
42
+ :sessionID,
43
+ :user_agent,
44
+ :accept_language
45
+ ].freeze
46
+ end
47
+ end
48
+
49
+ # The TelephoneVerification class handles fraud verification
50
+ # through MaxMind's Telephone Verification API
51
+ #
52
+ # See: http://www.maxmind.com/app/telephone_api
53
+ class TelephoneVerification < Base
54
+ # The MaxMind Telephone Verification API URL
55
+ set_api_url "https://www.maxmind.com/app/telephone_http"
56
+
57
+ # Required parameters for a Telephone Verification API call
58
+ set_required_params :l, :phone
59
+
60
+ # Optional parameters
61
+ def optional_params
62
+ [:l, :phone, :verify_code].freeze
63
+ end
64
+ end
65
+
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,6 @@
1
+ module Hamburglar
2
+ module Gateways
3
+ autoload :Base, 'hamburglar/gateways/base'
4
+ autoload :MaxMind, 'hamburglar/gateways/max_mind'
5
+ end
6
+ end
@@ -0,0 +1,61 @@
1
+ module Hamburglar
2
+ # Hamburglar::Report is the main class for generating fraud reports
3
+ class Report
4
+ # Parameters that will be used to generate this fraud report
5
+ attr_reader :params
6
+
7
+ # Response from gateway
8
+ attr_reader :response
9
+
10
+ def initialize(params = {})
11
+ @gateway = params.delete(:gateway) || Hamburglar.config.gateway
12
+ @params = params
13
+ @response = generate_report!
14
+ end
15
+
16
+ def method_missing(method, *args, &block)
17
+ if @response && @response[method.to_sym]
18
+ @response[method.to_sym]
19
+ else
20
+ super
21
+ end
22
+ end
23
+
24
+ def respond_to?(key)
25
+ @response.has_key?(key) || super
26
+ end
27
+
28
+ def fraud?
29
+ @fraud = true if @response.nil? || @response.empty?
30
+ return @fraud if @fraud
31
+ if Hamburglar.config.fraud_proc.nil?
32
+ @fraud = @response[:score].to_f >= Hamburglar.config.fraud_score.to_f
33
+ else
34
+ @fraud = Hamburglar.config.fraud_proc.call(self) == true
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def generate_report!
41
+ api = gateway.new(@params)
42
+ if api.valid?
43
+ api.submit
44
+ else
45
+ api.errors
46
+ end
47
+ end
48
+
49
+ def gateway
50
+ case @gateway.to_s
51
+ when /min_fraud/
52
+ Gateways::MaxMind::MinFraud
53
+ when /telephone/
54
+ Gateways::MaxMind::TelephoneVerification
55
+ else
56
+ raise Hamburglar::InvalidGateway, @gateway
57
+ end
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ module Hamburglar
2
+ VERSION = Version = '0.1.0'
3
+ end
data/lib/hamburglar.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'hamburglar/errors'
2
+
3
+ module Hamburglar
4
+ autoload :Version, 'hamburglar/version'
5
+ autoload :Config, 'hamburglar/config'
6
+ autoload :Report, 'hamburglar/report'
7
+ autoload :Gateways, 'hamburglar/gateways'
8
+
9
+ class << self
10
+ attr_accessor :config
11
+ end
12
+
13
+ def self.configure
14
+ yield config if block_given?
15
+ config
16
+ end
17
+
18
+ self.config = Config.new
19
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hamburglar
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - Joshua Priddle
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-06-03 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rspec
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: "2.6"
25
+ type: :development
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: 0.8.7
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: fakeweb
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 1.3.0
47
+ type: :development
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: vcr
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ version: "1.10"
58
+ type: :development
59
+ version_requirements: *id004
60
+ description: Hamburglar helps you prevent fraudulent orders
61
+ email: jpriddle@site5.com
62
+ executables: []
63
+
64
+ extensions: []
65
+
66
+ extra_rdoc_files:
67
+ - README.markdown
68
+ files:
69
+ - Rakefile
70
+ - README.markdown
71
+ - lib/cacert.pem
72
+ - lib/hamburglar/config.rb
73
+ - lib/hamburglar/errors.rb
74
+ - lib/hamburglar/gateways/base.rb
75
+ - lib/hamburglar/gateways/max_mind.rb
76
+ - lib/hamburglar/gateways.rb
77
+ - lib/hamburglar/report.rb
78
+ - lib/hamburglar/version.rb
79
+ - lib/hamburglar.rb
80
+ has_rdoc: true
81
+ homepage: https://github.com/site5/hamburglar
82
+ licenses: []
83
+
84
+ post_install_message:
85
+ rdoc_options:
86
+ - --charset=UTF-8
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: "0"
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: "0"
101
+ requirements: []
102
+
103
+ rubyforge_project:
104
+ rubygems_version: 1.6.2
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: Hamburglar helps you prevent fraudulent orders
108
+ test_files: []
109
+