paid 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -1
- data/.travis.yml +16 -0
- data/History.txt +4 -0
- data/README.md +58 -0
- data/Rakefile +9 -29
- data/VERSION +1 -0
- data/bin/paid-console +7 -0
- data/gemfiles/default-with-activesupport.gemfile +10 -0
- data/gemfiles/json.gemfile +12 -0
- data/gemfiles/yajl.gemfile +12 -0
- data/lib/paid.rb +129 -177
- data/lib/paid/account.rb +14 -1
- data/lib/paid/api_class.rb +336 -0
- data/lib/paid/api_list.rb +47 -0
- data/lib/paid/api_resource.rb +8 -25
- data/lib/paid/api_singleton.rb +5 -0
- data/lib/paid/customer.rb +36 -21
- data/lib/paid/errors/api_error.rb +6 -0
- data/lib/paid/event.rb +22 -1
- data/lib/paid/invoice.rb +16 -21
- data/lib/paid/plan.rb +18 -2
- data/lib/paid/subscription.rb +17 -11
- data/lib/paid/transaction.rb +19 -12
- data/lib/paid/util.rb +53 -106
- data/lib/paid/version.rb +1 -1
- data/paid.gemspec +10 -11
- data/tasks/api_test.rb +187 -0
- data/test/mock_resource.rb +69 -0
- data/test/paid/account_test.rb +41 -4
- data/test/paid/api_class_test.rb +412 -0
- data/test/paid/api_list_test.rb +17 -0
- data/test/paid/api_resource_test.rb +13 -343
- data/test/paid/api_singleton_test.rb +12 -0
- data/test/paid/authentication_test.rb +50 -0
- data/test/paid/customer_test.rb +189 -29
- data/test/paid/event_test.rb +74 -0
- data/test/paid/invoice_test.rb +101 -20
- data/test/paid/plan_test.rb +84 -8
- data/test/paid/status_codes_test.rb +63 -0
- data/test/paid/subscription_test.rb +100 -20
- data/test/paid/transaction_test.rb +110 -37
- data/test/paid/util_test.rb +15 -24
- data/test/test_data.rb +144 -93
- data/test/test_helper.rb +6 -4
- metadata +32 -26
- data/Gemfile.lock +0 -54
- data/README.rdoc +0 -35
- data/lib/data/ca-certificates.crt +0 -0
- data/lib/paid/alias.rb +0 -16
- data/lib/paid/api_operations/create.rb +0 -17
- data/lib/paid/api_operations/delete.rb +0 -11
- data/lib/paid/api_operations/list.rb +0 -17
- data/lib/paid/api_operations/update.rb +0 -57
- data/lib/paid/certificate_blacklist.rb +0 -55
- data/lib/paid/list_object.rb +0 -37
- data/lib/paid/paid_object.rb +0 -187
- data/lib/paid/singleton_api_resource.rb +0 -20
- data/lib/tasks/paid_tasks.rake +0 -4
- data/test/paid/alias_test.rb +0 -22
- data/test/paid/certificate_blacklist_test.rb +0 -18
- data/test/paid/list_object_test.rb +0 -16
- data/test/paid/paid_object_test.rb +0 -27
- data/test/paid/properties_test.rb +0 -103
data/test/test_helper.rb
CHANGED
@@ -4,6 +4,7 @@ require 'mocha/setup'
|
|
4
4
|
require 'stringio'
|
5
5
|
require 'shoulda'
|
6
6
|
require File.expand_path('../test_data', __FILE__)
|
7
|
+
require File.expand_path('../mock_resource', __FILE__)
|
7
8
|
|
8
9
|
# monkeypatch request methods
|
9
10
|
module Paid
|
@@ -14,12 +15,13 @@ module Paid
|
|
14
15
|
end
|
15
16
|
|
16
17
|
def self.execute_request(opts)
|
17
|
-
|
18
|
+
headers = opts[:headers]
|
18
19
|
post_params = opts[:payload]
|
19
20
|
case opts[:method]
|
20
|
-
when :get then @mock_rest_client.get opts[:url],
|
21
|
-
when :
|
22
|
-
when :
|
21
|
+
when :get then @mock_rest_client.get opts[:url], headers, post_params
|
22
|
+
when :put then @mock_rest_client.put opts[:url], headers, post_params
|
23
|
+
when :post then @mock_rest_client.post opts[:url], headers, post_params
|
24
|
+
when :delete then @mock_rest_client.delete opts[:url], headers, post_params
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
+
- Jon Calhoun
|
7
8
|
- Ryan Jackson
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2015-
|
12
|
+
date: 2015-03-09 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: rest-client
|
@@ -117,27 +118,31 @@ dependencies:
|
|
117
118
|
description: Paid is the programmatic way to manage payments. See https://paidapi.com
|
118
119
|
for details.
|
119
120
|
email:
|
121
|
+
- joncalhoun@gmail.com
|
120
122
|
- ryan@paidapi.com
|
121
|
-
executables:
|
123
|
+
executables:
|
124
|
+
- paid-console
|
122
125
|
extensions: []
|
123
126
|
extra_rdoc_files: []
|
124
127
|
files:
|
125
128
|
- ".gitignore"
|
129
|
+
- ".travis.yml"
|
126
130
|
- Gemfile
|
127
|
-
-
|
131
|
+
- History.txt
|
128
132
|
- MIT-LICENSE
|
129
|
-
- README.
|
133
|
+
- README.md
|
130
134
|
- Rakefile
|
131
|
-
-
|
135
|
+
- VERSION
|
136
|
+
- bin/paid-console
|
137
|
+
- gemfiles/default-with-activesupport.gemfile
|
138
|
+
- gemfiles/json.gemfile
|
139
|
+
- gemfiles/yajl.gemfile
|
132
140
|
- lib/paid.rb
|
133
141
|
- lib/paid/account.rb
|
134
|
-
- lib/paid/
|
135
|
-
- lib/paid/
|
136
|
-
- lib/paid/api_operations/delete.rb
|
137
|
-
- lib/paid/api_operations/list.rb
|
138
|
-
- lib/paid/api_operations/update.rb
|
142
|
+
- lib/paid/api_class.rb
|
143
|
+
- lib/paid/api_list.rb
|
139
144
|
- lib/paid/api_resource.rb
|
140
|
-
- lib/paid/
|
145
|
+
- lib/paid/api_singleton.rb
|
141
146
|
- lib/paid/customer.rb
|
142
147
|
- lib/paid/errors/api_connection_error.rb
|
143
148
|
- lib/paid/errors/api_error.rb
|
@@ -146,26 +151,25 @@ files:
|
|
146
151
|
- lib/paid/errors/paid_error.rb
|
147
152
|
- lib/paid/event.rb
|
148
153
|
- lib/paid/invoice.rb
|
149
|
-
- lib/paid/list_object.rb
|
150
|
-
- lib/paid/paid_object.rb
|
151
154
|
- lib/paid/plan.rb
|
152
|
-
- lib/paid/singleton_api_resource.rb
|
153
155
|
- lib/paid/subscription.rb
|
154
156
|
- lib/paid/transaction.rb
|
155
157
|
- lib/paid/util.rb
|
156
158
|
- lib/paid/version.rb
|
157
|
-
- lib/tasks/paid_tasks.rake
|
158
159
|
- paid.gemspec
|
160
|
+
- tasks/api_test.rb
|
161
|
+
- test/mock_resource.rb
|
159
162
|
- test/paid/account_test.rb
|
160
|
-
- test/paid/
|
163
|
+
- test/paid/api_class_test.rb
|
164
|
+
- test/paid/api_list_test.rb
|
161
165
|
- test/paid/api_resource_test.rb
|
162
|
-
- test/paid/
|
166
|
+
- test/paid/api_singleton_test.rb
|
167
|
+
- test/paid/authentication_test.rb
|
163
168
|
- test/paid/customer_test.rb
|
169
|
+
- test/paid/event_test.rb
|
164
170
|
- test/paid/invoice_test.rb
|
165
|
-
- test/paid/list_object_test.rb
|
166
|
-
- test/paid/paid_object_test.rb
|
167
171
|
- test/paid/plan_test.rb
|
168
|
-
- test/paid/
|
172
|
+
- test/paid/status_codes_test.rb
|
169
173
|
- test/paid/subscription_test.rb
|
170
174
|
- test/paid/transaction_test.rb
|
171
175
|
- test/paid/util_test.rb
|
@@ -196,16 +200,18 @@ signing_key:
|
|
196
200
|
specification_version: 4
|
197
201
|
summary: Ruby bindings for Paid API
|
198
202
|
test_files:
|
203
|
+
- test/mock_resource.rb
|
199
204
|
- test/paid/account_test.rb
|
200
|
-
- test/paid/
|
205
|
+
- test/paid/api_class_test.rb
|
206
|
+
- test/paid/api_list_test.rb
|
201
207
|
- test/paid/api_resource_test.rb
|
202
|
-
- test/paid/
|
208
|
+
- test/paid/api_singleton_test.rb
|
209
|
+
- test/paid/authentication_test.rb
|
203
210
|
- test/paid/customer_test.rb
|
211
|
+
- test/paid/event_test.rb
|
204
212
|
- test/paid/invoice_test.rb
|
205
|
-
- test/paid/list_object_test.rb
|
206
|
-
- test/paid/paid_object_test.rb
|
207
213
|
- test/paid/plan_test.rb
|
208
|
-
- test/paid/
|
214
|
+
- test/paid/status_codes_test.rb
|
209
215
|
- test/paid/subscription_test.rb
|
210
216
|
- test/paid/transaction_test.rb
|
211
217
|
- test/paid/util_test.rb
|
data/Gemfile.lock
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
paid (0.1.0)
|
5
|
-
json (~> 1.8.1)
|
6
|
-
mime-types (>= 1.25, < 3.0)
|
7
|
-
rest-client (~> 1.4)
|
8
|
-
|
9
|
-
GEM
|
10
|
-
remote: https://rubygems.org/
|
11
|
-
specs:
|
12
|
-
activesupport (4.2.0)
|
13
|
-
i18n (~> 0.7)
|
14
|
-
json (~> 1.7, >= 1.7.7)
|
15
|
-
minitest (~> 5.1)
|
16
|
-
thread_safe (~> 0.3, >= 0.3.4)
|
17
|
-
tzinfo (~> 1.1)
|
18
|
-
bourne (1.5.0)
|
19
|
-
mocha (>= 0.13.2, < 0.15)
|
20
|
-
i18n (0.7.0)
|
21
|
-
json (1.8.2)
|
22
|
-
metaclass (0.0.4)
|
23
|
-
mime-types (2.4.3)
|
24
|
-
minitest (5.5.1)
|
25
|
-
mocha (0.13.3)
|
26
|
-
metaclass (~> 0.0.1)
|
27
|
-
netrc (0.10.2)
|
28
|
-
power_assert (0.2.2)
|
29
|
-
rake (10.4.2)
|
30
|
-
rest-client (1.7.2)
|
31
|
-
mime-types (>= 1.16, < 3.0)
|
32
|
-
netrc (~> 0.7)
|
33
|
-
shoulda (3.4.0)
|
34
|
-
shoulda-context (~> 1.0, >= 1.0.1)
|
35
|
-
shoulda-matchers (~> 1.0, >= 1.4.1)
|
36
|
-
shoulda-context (1.2.1)
|
37
|
-
shoulda-matchers (1.5.6)
|
38
|
-
activesupport (>= 3.0.0)
|
39
|
-
bourne (~> 1.3)
|
40
|
-
test-unit (3.0.9)
|
41
|
-
power_assert
|
42
|
-
thread_safe (0.3.4)
|
43
|
-
tzinfo (1.2.2)
|
44
|
-
thread_safe (~> 0.1)
|
45
|
-
|
46
|
-
PLATFORMS
|
47
|
-
ruby
|
48
|
-
|
49
|
-
DEPENDENCIES
|
50
|
-
mocha (~> 0.13.2)
|
51
|
-
paid!
|
52
|
-
rake
|
53
|
-
shoulda (~> 3.4.0)
|
54
|
-
test-unit
|
data/README.rdoc
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
= Paid Ruby bindings
|
2
|
-
|
3
|
-
== Installation
|
4
|
-
|
5
|
-
gem 'paid'
|
6
|
-
|
7
|
-
== Requirements
|
8
|
-
|
9
|
-
* Ruby 1.8.7 or above. (Ruby 1.8.6 may work if you load
|
10
|
-
ActiveSupport.) For Ruby versions before 1.9.2, you'll need to add this to your Gemfile:
|
11
|
-
|
12
|
-
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.2')
|
13
|
-
gem 'rest-client', '~> 1.6.8'
|
14
|
-
end
|
15
|
-
|
16
|
-
|
17
|
-
* rest-client, json
|
18
|
-
|
19
|
-
== Mirrors
|
20
|
-
|
21
|
-
The paid gem is mirrored on Rubygems, so you should be able to
|
22
|
-
install it via <tt>gem install paid</tt> if desired.
|
23
|
-
|
24
|
-
Note that if you are installing via bundler, you should be sure to use the https
|
25
|
-
rubygems source in your Gemfile, as any gems fetched over http could potentially be
|
26
|
-
compromised in transit and alter the code of gems fetched securely over https:
|
27
|
-
|
28
|
-
source 'https://rubygems.org'
|
29
|
-
|
30
|
-
gem 'rails'
|
31
|
-
gem 'paid'
|
32
|
-
|
33
|
-
== Development
|
34
|
-
|
35
|
-
Test cases can be run with: `bundle exec rake test`
|
File without changes
|
data/lib/paid/alias.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
module Paid
|
2
|
-
class Alias < APIResource
|
3
|
-
include Paid::APIOperations::Update
|
4
|
-
|
5
|
-
def self.retrieve(id, api_key=nil)
|
6
|
-
customer_alias = super(id, api_key)
|
7
|
-
if customer_alias.respond_to? "error"
|
8
|
-
customer_alias
|
9
|
-
else
|
10
|
-
instance = Paid::Customer.new(customer_alias.id, api_key)
|
11
|
-
instance.refresh
|
12
|
-
instance
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Paid
|
2
|
-
module APIOperations
|
3
|
-
module Create
|
4
|
-
module ClassMethods
|
5
|
-
def create(params={}, opts={})
|
6
|
-
api_key, headers = Util.parse_opts(opts)
|
7
|
-
response, api_key = Paid.request(:post, self.api_url, api_key, params, headers)
|
8
|
-
Util.convert_to_paid_object(response, api_key)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.included(base)
|
13
|
-
base.extend(ClassMethods)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
module Paid
|
2
|
-
module APIOperations
|
3
|
-
module Delete
|
4
|
-
def delete(params = {}, opts={})
|
5
|
-
api_key, headers = Util.parse_opts(opts)
|
6
|
-
response, api_key = Paid.request(:delete, api_url, api_key || @api_key, params, headers)
|
7
|
-
refresh_from(response, api_key)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Paid
|
2
|
-
module APIOperations
|
3
|
-
module List
|
4
|
-
module ClassMethods
|
5
|
-
def all(filters={}, opts={})
|
6
|
-
api_key, headers = Util.parse_opts(opts)
|
7
|
-
response, api_key = Paid.request(:get, api_url, api_key, filters, headers)
|
8
|
-
Util.convert_to_paid_object(response, api_key)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.included(base)
|
13
|
-
base.extend(ClassMethods)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
module Paid
|
2
|
-
module APIOperations
|
3
|
-
module Update
|
4
|
-
def save(opts={})
|
5
|
-
values = serialize_params(self).merge(opts)
|
6
|
-
|
7
|
-
if @values[:properties]
|
8
|
-
values[:properties] = serialize_properties
|
9
|
-
end
|
10
|
-
|
11
|
-
if values.length > 0
|
12
|
-
values.delete(:id)
|
13
|
-
|
14
|
-
response, api_key = Paid.request(:post, api_url, @api_key, values)
|
15
|
-
refresh_from(response, api_key)
|
16
|
-
end
|
17
|
-
self
|
18
|
-
end
|
19
|
-
|
20
|
-
def serialize_properties
|
21
|
-
if @unsaved_values.include?(:properties)
|
22
|
-
# the properties object has been reassigned
|
23
|
-
# i.e. as object.properties = {key => val}
|
24
|
-
properties_update = @values[:properties] # new hash
|
25
|
-
new_keys = properties_update.keys.map(&:to_sym)
|
26
|
-
# remove keys at the server, but not known locally
|
27
|
-
keys_to_unset = @previous_properties.keys - new_keys
|
28
|
-
keys_to_unset.each {|key| properties_update[key] = ''}
|
29
|
-
|
30
|
-
properties_update
|
31
|
-
else
|
32
|
-
# properties is a PaidObject, and can be serialized normally
|
33
|
-
serialize_params(@values[:properties])
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def serialize_params(obj)
|
38
|
-
case obj
|
39
|
-
when nil
|
40
|
-
''
|
41
|
-
when PaidObject
|
42
|
-
unsaved_keys = obj.instance_variable_get(:@unsaved_values)
|
43
|
-
obj_values = obj.instance_variable_get(:@values)
|
44
|
-
update_hash = {}
|
45
|
-
|
46
|
-
unsaved_keys.each do |k|
|
47
|
-
update_hash[k] = serialize_params(obj_values[k])
|
48
|
-
end
|
49
|
-
|
50
|
-
update_hash
|
51
|
-
else
|
52
|
-
obj
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'uri'
|
2
|
-
require 'digest/sha1'
|
3
|
-
|
4
|
-
module Paid
|
5
|
-
module CertificateBlacklist
|
6
|
-
|
7
|
-
BLACKLIST = {
|
8
|
-
"api.paidapi.com" => [
|
9
|
-
'',
|
10
|
-
],
|
11
|
-
"revoked.paidapi.com" => [
|
12
|
-
'',
|
13
|
-
]
|
14
|
-
}
|
15
|
-
|
16
|
-
# Preflight the SSL certificate presented by the backend. This isn't 100%
|
17
|
-
# bulletproof, in that we're not actually validating the transport used to
|
18
|
-
# communicate with Paid, merely that the first attempt to does not use a
|
19
|
-
# revoked certificate.
|
20
|
-
|
21
|
-
# Unfortunately the interface to OpenSSL doesn't make it easy to check the
|
22
|
-
# certificate before sending potentially sensitive data on the wire. This
|
23
|
-
# approach raises the bar for an attacker significantly.
|
24
|
-
|
25
|
-
def self.check_ssl_cert(uri, ca_file)
|
26
|
-
uri = URI.parse(uri)
|
27
|
-
|
28
|
-
sock = TCPSocket.new(uri.host, uri.port)
|
29
|
-
ctx = OpenSSL::SSL::SSLContext.new
|
30
|
-
ctx.set_params(:verify_mode => OpenSSL::SSL::VERIFY_PEER,
|
31
|
-
:ca_file => ca_file)
|
32
|
-
|
33
|
-
socket = OpenSSL::SSL::SSLSocket.new(sock, ctx)
|
34
|
-
socket.connect
|
35
|
-
|
36
|
-
certificate = socket.peer_cert.to_der
|
37
|
-
fingerprint = Digest::SHA1.hexdigest(certificate)
|
38
|
-
|
39
|
-
if blacklisted_certs = BLACKLIST[uri.host]
|
40
|
-
if blacklisted_certs.include?(fingerprint)
|
41
|
-
raise APIConnectionError.new(
|
42
|
-
"Invalid server certificate. You tried to connect to a server that" +
|
43
|
-
"has a revoked SSL certificate, which means we cannot securely send" +
|
44
|
-
"data to that server. Please email support@paidapi.com if you need" +
|
45
|
-
"help connecting to the correct API server."
|
46
|
-
)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
socket.close
|
51
|
-
|
52
|
-
return true
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
data/lib/paid/list_object.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
module Paid
|
2
|
-
class ListObject < PaidObject
|
3
|
-
|
4
|
-
def [](k)
|
5
|
-
case k
|
6
|
-
when String, Symbol
|
7
|
-
super
|
8
|
-
else
|
9
|
-
raise ArgumentError.new("You tried to access the #{k.inspect} index, but ListObject types only support String keys. (HINT: List calls return an object with a 'data' (which is the data array). You likely want to call #data[#{k.inspect}])")
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def each(&blk)
|
14
|
-
self.data.each(&blk)
|
15
|
-
end
|
16
|
-
|
17
|
-
def retrieve(id, api_key=nil)
|
18
|
-
api_key ||= @api_key
|
19
|
-
response, api_key = Paid.request(:get,"#{url}/#{CGI.escape(id)}", api_key)
|
20
|
-
Util.convert_to_paid_object(response, api_key)
|
21
|
-
end
|
22
|
-
|
23
|
-
def create(params={}, opts={})
|
24
|
-
api_key, headers = Util.parse_opts(opts)
|
25
|
-
api_key ||= @api_key
|
26
|
-
response, api_key = Paid.request(:post, url, api_key, params, headers)
|
27
|
-
Util.convert_to_paid_object(response, api_key)
|
28
|
-
end
|
29
|
-
|
30
|
-
def all(params={}, opts={})
|
31
|
-
api_key, headers = Util.parse_opts(opts)
|
32
|
-
api_key ||= @api_key
|
33
|
-
response, api_key = Paid.request(:get, url, api_key, params, headers)
|
34
|
-
Util.convert_to_paid_object(response, api_key)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|