fake_pin 0.0.1

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: b26c0fbfa19cf74b4521c19774b1e844ec5623b7
4
+ data.tar.gz: 65ffac6cf6f96872dd30930e5f8f0681a69ff7cc
5
+ SHA512:
6
+ metadata.gz: ea5167e1da065cc289fc2160b78427ca65c7ed9779cf0f3242c1efdcd1d0c4fe9ea07d472393c1c4805e8fe14090e8ff3160d072602ed4ed2e30fdefc12343c3
7
+ data.tar.gz: ee02b374c8fb12317fc002a2c28a0d478d92e727811faad003bcb012fe0f1e741301d373b234477e0ebc3887053e09488a8d88a65152db202d272c43b0d9ab18
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --profile
3
+ -Ilib
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fake_pin.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Keith Pitt
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # FakePin
2
+
3
+ A basic implmentation of the Pin Payments REST API. This is great for when you want to test your API client or want an offline version of the API for automated testing.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'fake_pin'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```bash
22
+ $ gem install fake_pin
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ In your Rails Routes folder:
28
+
29
+ ```ruby
30
+ YourApp::Application.routes.draw do
31
+ # ...
32
+
33
+ if Rails.env.development? || Rails.env.test?
34
+ constraints :host => /pin.your-app.dev/ do
35
+ mount FakePin::Rack.new => '/'
36
+ end
37
+ end
38
+ end
39
+ ```
40
+
41
+ Or you can run it as a standlone server. Currently it only support WEBrick and runs on port 9000.
42
+
43
+ ```bash
44
+ $ fake_pin
45
+ ```
46
+
47
+ You should then be able to cURL charges like so:
48
+
49
+ ```bash
50
+ curl localhost:9000/1/charges -u your-secret-api-key: -d "amount=400" -d "currency=AUD" -d "description=test charge" -d "email=roland@pin.net.au" -d "ip_address=203.192.1.172" -d "card[number]=5520000000000000" -d "card[expiry_month]=05" -d "card[expiry_year]=2014" -d "card[cvc]=123" -d "card[name]=Roland Robot" -d "card[address_line1]=42 Sevenoaks St" -d "card[address_line2]=" -d "card[address_city]=Lathlain" -d "card[address_postcode]=6454" -d "card[address_state]=WA" -d "card[address_country]=Australia"
51
+ ```
52
+
53
+ ## Contributing
54
+
55
+ 1. Fork it
56
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
57
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
58
+ 4. Push to the branch (`git push origin my-new-feature`)
59
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/fake_pin ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Set the process name before we go to far in
4
+ $PROGRAM_NAME = 'fake_pin'
5
+
6
+ # Add the fake_pin lib directory to the load path
7
+ root_dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
8
+ lib_dir = File.join(root_dir, 'lib')
9
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
10
+
11
+ require 'fake_pin'
12
+ require 'rack'
13
+
14
+ Rack::Handler::WEBrick.run(
15
+ FakePin::Rack.new, :Port => 9000
16
+ )
data/fake_pin.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fake_pin/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "fake_pin"
8
+ spec.version = FakePin::VERSION
9
+ spec.authors = ["Keith Pitt"]
10
+ spec.email = ["me@keithpitt.com"]
11
+ spec.description = %q{A rack-mountable version of the Pin Payments API}
12
+ spec.summary = %q{A rack-mountable version of the Pin Payments API}
13
+ spec.homepage = "https://github.com/keithpitt/fake_pin"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'rack'
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ end
@@ -0,0 +1,64 @@
1
+ module FakePin
2
+ class Card
3
+ class UnrecognisedCardSchemeError < RuntimeError; end
4
+
5
+ REQUIRED_PARAMS = :number, :expiry_month, :expiry_year, :name, :address_line1,
6
+ :address_city, :address_postcode, :address_state, :address_country
7
+
8
+ SCHEMES = {
9
+ 'visa' => /^4\d{12}(\d{3})?$/,
10
+ 'master' => /^(5[1-5]\d{4}|677189)\d{10}$/,
11
+ 'discover' => /^(6011|65\d{2}|64[4-9]\d)\d{12}|(62\d{14})$/,
12
+ 'american_express' => /^3[47]\d{13}$/,
13
+ 'diners_club' => /^3(0[0-5]|[68]\d)\d{11}$/,
14
+ 'jcb' => /^35(28|29|[3-8]\d)\d{12}$/,
15
+ 'switch' => /^6759\d{12}(\d{2,3})?$/,
16
+ 'solo' => /^6767\d{12}(\d{2,3})?$/,
17
+ 'dankort' => /^5019\d{12}$/,
18
+ 'maestro' => /^(5[06-8]|6\d)\d{10,17}$/,
19
+ 'forbrugsforeningen' => /^600722\d{10}$/,
20
+ 'laser' => /^(6304|6706|6709|6771(?!89))\d{8}(\d{4}|\d{6,7})?$/
21
+ }
22
+
23
+ def self.create(params)
24
+ new(params).create
25
+ end
26
+
27
+ def initialize(params)
28
+ @params = params
29
+ end
30
+
31
+ def create
32
+ @params.require(*REQUIRED_PARAMS)
33
+
34
+ number = @params['number'].to_s.gsub(/[^0-9]+/, '')
35
+
36
+ {
37
+ "token" => Token.generate('card'),
38
+ "display_number" => obfuscate_card_number(number),
39
+ "expiry_month" => @params['expiry_month'],
40
+ "expiry_year" => @params['expiry_year'],
41
+ "name" => @params['name'],
42
+ "address_line1" => @params['address_line1'],
43
+ "address_line2" => @params['address_line2'],
44
+ "address_city" => @params['address_city'],
45
+ "address_postcode" => @params['address_postcode'],
46
+ "address_state" => @params['address_state'],
47
+ "address_country" => @params['address_country'],
48
+ "scheme" => card_scheme(number)
49
+ }
50
+ end
51
+
52
+ private
53
+
54
+ def card_scheme(number)
55
+ SCHEMES.each_pair { |scheme, regex| return scheme if number =~ regex }
56
+
57
+ raise UnrecognisedCardSchemeError
58
+ end
59
+
60
+ def obfuscate_card_number(card_number)
61
+ "XXXX-XXXX-XXXX-#{card_number[-4..-1]}"
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,30 @@
1
+ module FakePin
2
+ class Charge
3
+ def self.create(params)
4
+ new(params).create
5
+ end
6
+
7
+ def initialize(params)
8
+ @params = params
9
+ end
10
+
11
+ def create
12
+ @params.require(:amount, :description)
13
+ currency = @params["currency"] || "AUD"
14
+
15
+ { "token" => Token.generate('ch'),
16
+ "success" => true,
17
+ "amount" => @params['amount'],
18
+ "description" => @params['description'],
19
+ "currency" => currency,
20
+ "ip_address" => "203.192.1.172",
21
+ "email" => @params['email'],
22
+ "status_message" => "Success!",
23
+ "error_message" => nil,
24
+ "captured" => true,
25
+ "authorisation_expired" => false,
26
+ "transfer" => nil,
27
+ "created_at" => Time.now.to_s }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ module FakePin
2
+ class Customer
3
+ def self.create(params)
4
+ new(params).create
5
+ end
6
+
7
+ def initialize(params)
8
+ @params = params
9
+ end
10
+
11
+ def create
12
+ card = @params['card']
13
+ @params.require(:email, :card => Card::REQUIRED_PARAMS) if card.present?
14
+
15
+ response = { "token" => Token.generate('cus'),
16
+ "email" => @params['email'],
17
+ "created_at" => Time.now.to_s }
18
+
19
+ response['card'] = Card.create(card) if card.present?
20
+
21
+ response
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,47 @@
1
+ module FakePin
2
+ class Params
3
+ class MissingParametersError < RuntimeError
4
+ attr_reader :parameters
5
+
6
+ def initialize(parameters, message = nil)
7
+ @parameters = parameters
8
+ super(message)
9
+ end
10
+ end
11
+
12
+ def initialize(params)
13
+ @params = params
14
+ end
15
+
16
+ def [](key)
17
+ value = @params[key]
18
+ if value.kind_of?(Hash)
19
+ self.class.new(value)
20
+ else
21
+ value
22
+ end
23
+ end
24
+
25
+ def require(*params)
26
+ missing_params = []
27
+ params.each do |param|
28
+ if param.kind_of?(Hash)
29
+ parent_key = param.keys.first
30
+ param[parent_key].each do |child_key|
31
+ if @params[parent_key.to_s][child_key.to_s].nil?
32
+ missing_params << child_key
33
+ end
34
+ end
35
+ else
36
+ if @params[param.to_s].nil?
37
+ missing_params << param
38
+ end
39
+ end
40
+ end
41
+
42
+ if missing_params.length > 0
43
+ raise MissingParametersError.new(missing_params)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,85 @@
1
+ require 'json'
2
+ require 'rack'
3
+
4
+ module FakePin
5
+ class Rack
6
+ def call(env)
7
+ request = ::Rack::Request.new(env)
8
+ method = env['REQUEST_METHOD']
9
+ path = env['PATH_INFO']
10
+
11
+ # Strip the first slash if there is one. When mounted in Rails, there is no slash.
12
+ # When running as a standlone rack app, there is one.
13
+ path = path.gsub(/\A\//, '')
14
+
15
+ params = if env['CONTENT_TYPE'] == "application/json"
16
+ Params.new(JSON.parse(request.body.read))
17
+ else
18
+ Params.new(request.params)
19
+ end
20
+
21
+ if path == "1/customers"
22
+ if method == "POST"
23
+ return render_response(201, Customer.create(params))
24
+ end
25
+ elsif path == "1/charges"
26
+ if method == "POST"
27
+ return render_response(201, Charge.create(params))
28
+ end
29
+ elsif path =~ /1\/cards(\.json)?/
30
+ is_jsonp = (method == "GET" && params['_method'] == "POST")
31
+
32
+ if method == "POST" || is_jsonp
33
+ return render_response(201, Card.create(params), :callback => is_jsonp ? params['callback'] : nil)
34
+ end
35
+ end
36
+
37
+ render_404
38
+ rescue Params::MissingParametersError => e
39
+ messages = e.parameters.map do |param|
40
+ { :code => "#{param}_invalid", :message => "#{param} is required", :param => param }
41
+ end
42
+
43
+ render_error 422, 'invalid_resource', 'One or more parameters were missing or invalid.', messages
44
+ rescue => e
45
+ render_error 500, 'fake_pin_exception', "FakePin broke with: #{e.class.name}:#{e.message}"
46
+ end
47
+
48
+ private
49
+
50
+ def render_404
51
+ render_error(404, "invalid_resource", "The resource you requested could not be found")
52
+ end
53
+
54
+ def render_response(status, response, options = {})
55
+ if options[:callback]
56
+ render_jsonp(status, { :response => response }, options[:callback])
57
+ else
58
+ render_json(status, :response => response)
59
+ end
60
+ end
61
+
62
+ def render_error(status, error, description, messages = nil)
63
+ response = { :error => error, :error_description => description }
64
+ response[:messages] = messages unless messages.nil?
65
+
66
+ render_json(status, response)
67
+ end
68
+
69
+ def render_jsonp(status, json, callback)
70
+ [
71
+ status,
72
+ {"Content-Type" => 'text/javascript'},
73
+ ["#{callback}(#{JSON.dump(json)})"]
74
+ ]
75
+ end
76
+
77
+ def render_json(status, json)
78
+ [
79
+ status,
80
+ {"Content-Type" => 'text/json'},
81
+ [JSON.dump(json)]
82
+ ]
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,15 @@
1
+ module FakePin
2
+ class Token
3
+ def self.generate(prefix)
4
+ new(prefix).generate
5
+ end
6
+
7
+ def initialize(prefix)
8
+ @prefix = prefix
9
+ end
10
+
11
+ def generate
12
+ "#{@prefix}_#{Time.now.to_f.to_s.gsub(/\./, '')}"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module FakePin
2
+ VERSION = "0.0.1"
3
+ end
data/lib/fake_pin.rb ADDED
@@ -0,0 +1,9 @@
1
+ module FakePin
2
+ autoload :Card, "fake_pin/card"
3
+ autoload :Charge, "fake_pin/charge"
4
+ autoload :Customer, "fake_pin/customer"
5
+ autoload :Params, "fake_pin/params"
6
+ autoload :Rack, "fake_pin/rack"
7
+ autoload :Token, "fake_pin/token"
8
+ autoload :VERSION, "fake_pin/version"
9
+ end
@@ -0,0 +1,12 @@
1
+ require 'bundler/setup'
2
+ require 'fake_pin'
3
+
4
+ Dir[SPEC_PATH.join("support/**/*.rb")].each { |f| require f }
5
+
6
+ RSpec.configure do |config|
7
+ # Run specs in random order to surface order dependencies. If you find an
8
+ # order dependency and want to debug it, you can fix the order by providing
9
+ # the seed, which is printed after each run.
10
+ # --seed 1234
11
+ config.order = "random"
12
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fake_pin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Keith Pitt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A rack-mountable version of the Pin Payments API
70
+ email:
71
+ - me@keithpitt.com
72
+ executables:
73
+ - fake_pin
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .gitignore
78
+ - .rspec
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - bin/fake_pin
84
+ - fake_pin.gemspec
85
+ - lib/fake_pin.rb
86
+ - lib/fake_pin/card.rb
87
+ - lib/fake_pin/charge.rb
88
+ - lib/fake_pin/customer.rb
89
+ - lib/fake_pin/params.rb
90
+ - lib/fake_pin/rack.rb
91
+ - lib/fake_pin/token.rb
92
+ - lib/fake_pin/version.rb
93
+ - spec/spec_helper.rb
94
+ homepage: https://github.com/keithpitt/fake_pin
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.0.3
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: A rack-mountable version of the Pin Payments API
118
+ test_files:
119
+ - spec/spec_helper.rb