hamburglar 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+