suhovius-itunes-receipt 1.1.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: 8165f8d1e086ee0a062b699545ea24ff2bd3eae6
4
+ data.tar.gz: f7b34a091438598aee027f650f693079327e7259
5
+ SHA512:
6
+ metadata.gz: 476aebc331f25fead9423402f9487e20eb99ced306f195d677065d05d9783a2b3d5898217a8746dc63ad06a8c9dddf341bc6f662a686874d70857d696714f2f3
7
+ data.tar.gz: da1a9177737ab57564ca142a3440d6466c175d8fb32262e31d7b913009fe5620ee282d4608b7207328e54c157b2afab30f778e456f03ec6a5e7af55d1b3ab442
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+ Gemfile.lock
21
+
22
+ ## PROJECT::SPECIFIC
23
+ coverage*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format=documentation
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 nov matake
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,49 @@
1
+ = suhovius-itunes-receipt
2
+
3
+ Handle iTunes In App Purchase Receipt Verification.
4
+
5
+ == Please Note
6
+
7
+ This gem is clone of original itunes-receipt by nov matake https://github.com/nov/itunes-receipt
8
+
9
+ There are some changes that were needed for my project. So, I'd recommend using original gem since it might be already updated with fixes that I've added here at this copy.
10
+
11
+ == Installation
12
+
13
+ gem install suhovius-itunes-receipt
14
+
15
+ == Usage
16
+
17
+ require 'itunes/receipt'
18
+
19
+ # pass Base64 encoded raw receipt data which you received from your iOS app
20
+ receipt = Itunes::Receipt.verify! 'ewoJInNpZ25hdHVyZSIgPSAi...'
21
+ receipt.product_id # => 'com.example.products.100gems'
22
+ receipt.transaction_id # => '1234567890'
23
+ :
24
+
25
+ See lib/itunes/receipt.rb for more attributes.
26
+
27
+ If you want to accept iTunes sandbox receipts, do like this.
28
+ With <code>allow_sandbox_receipt</code> option specified, this gem post given receipt data to iTunes production first, and when iTunes production tells it's sandbox receipt, re-send it to iTunes sandbox again automatically.
29
+ Without this option, this gem just raises an exception.
30
+
31
+ receipt = Itunes::Receipt.verify! 'ewoJInNpZ25hdHVyZSIgPSAi...', :allow_sandbox_receipt
32
+ receipt.sandbox? # => true/false
33
+
34
+ If you want to accept ONLY iTunes sandbox receipts (in your stable server etc.), call <code>Itunes.sandbox!</code> somewhere before you call <code>Itunes::Receipt.verify!</code>.
35
+ Then all verification call after that goes to iTunes sandbox, until you do <code>Itunes.sandbox = false</code>.
36
+
37
+ == Note on Patches/Pull Requests
38
+
39
+ * Fork the project.
40
+ * Make your feature addition or bug fix.
41
+ * Add tests for it. This is important so I don't break it in a
42
+ future version unintentionally.
43
+ * Commit, do not mess with rakefile, version, or history.
44
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
45
+ * Send me a pull request. Bonus points for topic branches.
46
+
47
+ == Copyright
48
+
49
+ Copyright (c) 2011 nov matake. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ namespace :coverage do
8
+ desc "Open coverage report"
9
+ task :report do
10
+ require 'simplecov'
11
+ `open "#{File.join SimpleCov.coverage_path, 'index.html'}"`
12
+ end
13
+ end
14
+
15
+ task :spec do
16
+ Rake::Task[:'coverage:report'].invoke unless ENV['TRAVIS_RUBY_VERSION']
17
+ end
18
+
19
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.1.1
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'suhovius-itunes-receipt'
6
+ s.description = %q{Handle iTunes In App Purchase Receipt Verification}
7
+ s.summary = %q{Handle iTunes In App Purchase Receipt Verification}
8
+ s.version = File.read(File.join(File.dirname(__FILE__), 'VERSION'))
9
+ s.authors = ['nov matake', 'suhovius']
10
+ s.email = 'nov@matake.jp'
11
+ s.homepage = 'https://github.com/suhovius/itunes-receipt'
12
+ s.require_paths = ['lib']
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.add_dependency 'json', '>= 1.4.3'
17
+ s.add_dependency 'restclient_with_cert'
18
+ s.add_dependency 'activesupport', '>= 2.3'
19
+ s.add_dependency 'i18n'
20
+ s.add_development_dependency 'rake', '>= 0.8'
21
+ s.add_development_dependency 'rspec', '>= 2'
22
+ s.add_development_dependency 'fakeweb', '>= 1.3.0'
23
+ s.add_development_dependency 'simplecov'
24
+ end
data/lib/itunes.rb ADDED
@@ -0,0 +1,39 @@
1
+ require 'json'
2
+ require 'active_support/all'
3
+ require 'restclient_with_cert'
4
+
5
+ module Itunes
6
+
7
+ ENDPOINT = {
8
+ :production => 'https://buy.itunes.apple.com/verifyReceipt',
9
+ :sandbox => 'https://sandbox.itunes.apple.com/verifyReceipt'
10
+ }
11
+
12
+ def self.endpoint
13
+ ENDPOINT[itunes_env]
14
+ end
15
+
16
+ def self.itunes_env
17
+ sandbox? ? :sandbox : :production
18
+ end
19
+
20
+ def self.sandbox?
21
+ @@sandbox
22
+ end
23
+ def self.sandbox!
24
+ self.sandbox = true
25
+ end
26
+ def self.sandbox=(boolean)
27
+ @@sandbox = boolean
28
+ end
29
+ self.sandbox = false
30
+
31
+ def self.shared_secret
32
+ @@shared_secret
33
+ end
34
+ def self.shared_secret=(shared_secret)
35
+ @@shared_secret = shared_secret
36
+ end
37
+ self.shared_secret = nil
38
+
39
+ end
@@ -0,0 +1,188 @@
1
+ require 'itunes'
2
+
3
+ module Itunes
4
+ class Receipt
5
+ class VerificationFailed < StandardError
6
+ attr_reader :status
7
+ def initialize(attributes = {})
8
+ @status = attributes[:status]
9
+ super attributes[:exception]
10
+ end
11
+ end
12
+
13
+ class SandboxReceiptReceived < VerificationFailed; end;
14
+
15
+ class ReceiptServerOffline < VerificationFailed; end;
16
+
17
+ class ExpiredReceiptReceived < VerificationFailed
18
+ attr_reader :receipt
19
+ def initialize(attributes = {})
20
+ @receipt = attributes[:receipt]
21
+ super attributes
22
+ end
23
+ end
24
+
25
+ attr_reader(
26
+ :adam_id,
27
+ :app_item_id,
28
+ :application_version,
29
+ :bid,
30
+ :bundle_id,
31
+ :bvrs,
32
+ :download_id,
33
+ :expires_date,
34
+ :expires_date_ms,
35
+ :in_app,
36
+ :is_trial_period,
37
+ :itunes_env,
38
+ :latest,
39
+ :original,
40
+ :product_id,
41
+ :purchase_date,
42
+ :purchase_date_ms,
43
+ :purchase_date_pst,
44
+ :quantity,
45
+ :receipt_data,
46
+ :request_date,
47
+ :request_date_ms,
48
+ :request_date_pst,
49
+ :transaction_id,
50
+ :version_external_identifier,
51
+ )
52
+
53
+ def initialize(attributes = {})
54
+ receipt_attributes = attributes.with_indifferent_access[:receipt]
55
+ @adam_id = receipt_attributes[:adam_id]
56
+ @app_item_id = receipt_attributes[:app_item_id]
57
+ @application_version = receipt_attributes[:application_version]
58
+ @bid = receipt_attributes[:bid]
59
+ @bundle_id = receipt_attributes[:bundle_id]
60
+ @bvrs = receipt_attributes[:bvrs]
61
+ @download_id = receipt_attributes[:download_id]
62
+ @expires_date = if receipt_attributes[:expires_date]
63
+ Time.parse receipt_attributes[:expires_date].sub('Etc/GMT', 'GMT')
64
+ end
65
+ @expires_date_ms = if receipt_attributes[:expires_date_ms]
66
+ receipt_attributes[:expires_date_ms].to_i
67
+ end
68
+ @in_app = if receipt_attributes[:in_app]
69
+ receipt_attributes[:in_app].map { |ia| self.class.new(:receipt => ia) }
70
+ end
71
+ @is_trial_period = if receipt_attributes[:is_trial_period]
72
+ receipt_attributes[:is_trial_period] == "true"
73
+ end
74
+ @itunes_env = attributes[:itunes_env] || Itunes.itunes_env
75
+ @latest = case attributes[:latest_receipt_info]
76
+ when Hash
77
+ self.class.new(
78
+ :receipt => attributes[:latest_receipt_info],
79
+ :latest_receipt => attributes[:latest_receipt],
80
+ :receipt_type => :latest
81
+ )
82
+ when Array
83
+ attributes[:latest_receipt_info].collect do |latest_receipt_info|
84
+ self.class.new(
85
+ :receipt => latest_receipt_info,
86
+ :latest_receipt => attributes[:latest_receipt],
87
+ :receipt_type => :latest
88
+ )
89
+ end
90
+ end
91
+ @original = if receipt_attributes[:original_transaction_id] || receipt_attributes[:original_purchase_date]
92
+ self.class.new(:receipt => {
93
+ :transaction_id => receipt_attributes[:original_transaction_id],
94
+ :purchase_date => receipt_attributes[:original_purchase_date],
95
+ :purchase_date_ms => receipt_attributes[:original_purchase_date_ms],
96
+ :purchase_date_pst => receipt_attributes[:original_purchase_date_pst],
97
+ :application_version => receipt_attributes[:original_application_version]
98
+ })
99
+ end
100
+ @product_id = receipt_attributes[:product_id]
101
+ @purchase_date = if receipt_attributes[:purchase_date]
102
+ Time.parse receipt_attributes[:purchase_date].sub('Etc/GMT', 'GMT')
103
+ end
104
+ @purchase_date_ms = if receipt_attributes[:purchase_date_ms]
105
+ receipt_attributes[:purchase_date_ms].to_i
106
+ end
107
+ @purchase_date_pst = if receipt_attributes[:purchase_date_pst]
108
+ Time.parse receipt_attributes[:purchase_date_pst].sub('America/Los_Angeles', 'PST')
109
+ end
110
+ @quantity = if receipt_attributes[:quantity]
111
+ receipt_attributes[:quantity].to_i
112
+ end
113
+ @receipt_data = if attributes[:receipt_type] == :latest
114
+ attributes[:latest_receipt]
115
+ end
116
+ @request_date = if receipt_attributes[:request_date]
117
+ Time.parse receipt_attributes[:request_date].sub('Etc/', '')
118
+ end
119
+ @request_date_ms = if receipt_attributes[:request_date_ms]
120
+ receipt_attributes[:request_date_ms].to_i
121
+ end
122
+ @request_date_pst = if receipt_attributes[:request_date_pst]
123
+ Time.parse receipt_attributes[:request_date_pst].sub('America/Los_Angeles', 'PST')
124
+ end
125
+ @transaction_id = receipt_attributes[:transaction_id]
126
+ @version_external_identifier = receipt_attributes[:version_external_identifier]
127
+ end
128
+
129
+ def application_receipt?
130
+ !@bundle_id.nil?
131
+ end
132
+
133
+ def sandbox?
134
+ itunes_env == :sandbox
135
+ end
136
+
137
+ def last_in_app_receipt
138
+ self.in_app.last
139
+ end
140
+
141
+ def self.verify!(receipt_data, allow_sandbox_receipt = false)
142
+ request_data = {:'receipt-data' => receipt_data}
143
+ request_data.merge!(:password => Itunes.shared_secret) if Itunes.shared_secret
144
+ response = post_to_endpoint(request_data)
145
+ begin
146
+ successful_response(response)
147
+ rescue SandboxReceiptReceived => e
148
+ # Retry with sandbox, as per:
149
+ # http://developer.apple.com/library/ios/#technotes/tn2259/_index.html
150
+ # FAQ#16
151
+ if allow_sandbox_receipt
152
+ sandbox_response = post_to_endpoint(request_data, Itunes::ENDPOINT[:sandbox])
153
+ successful_response(
154
+ sandbox_response.merge(:itunes_env => :sandbox)
155
+ )
156
+ else
157
+ raise e
158
+ end
159
+ end
160
+ end
161
+
162
+ private
163
+
164
+ def self.post_to_endpoint(request_data, endpoint = Itunes.endpoint)
165
+ response = RestClient.post(
166
+ endpoint,
167
+ request_data.to_json
168
+ )
169
+ response = JSON.parse(response).with_indifferent_access
170
+ end
171
+
172
+ def self.successful_response(response)
173
+ case response[:status]
174
+ when 0
175
+ new response
176
+ when 21005
177
+ raise ReceiptServerOffline.new(response)
178
+ when 21006
179
+ raise ExpiredReceiptReceived.new(response)
180
+ when 21007
181
+ raise SandboxReceiptReceived.new(response)
182
+ else
183
+ raise VerificationFailed.new(response)
184
+ end
185
+ end
186
+
187
+ end
188
+ end
@@ -0,0 +1,135 @@
1
+ {
2
+ "environment": "Sandbox",
3
+ "latest_receipt": "BASE64ENCODED RECEIPT WAS HERE",
4
+ "latest_receipt_info": [{
5
+ "expires_date": "2014-11-12 15:10:33 Etc/GMT",
6
+ "expires_date_ms": "1415805033000",
7
+ "expires_date_pst": "2014-11-12 07:10:33 America/Los_Angeles",
8
+ "is_trial_period": "true",
9
+ "original_purchase_date": "2014-11-12 15:07:34 Etc/GMT",
10
+ "original_purchase_date_ms": "1415804854000",
11
+ "original_purchase_date_pst": "2014-11-12 07:07:34 America/Los_Angeles",
12
+ "original_transaction_id": "1000000131413546",
13
+ "product_id": "com.musteus.musteus.subscription.month",
14
+ "purchase_date": "2014-11-12 15:25:30 Etc/GMT",
15
+ "purchase_date_ms": "1415805930044",
16
+ "purchase_date_pst": "2014-11-12 07:25:30 America/Los_Angeles",
17
+ "quantity": "1",
18
+ "transaction_id": "1000000131413546",
19
+ "web_order_line_item_id": "1000000028817186"
20
+ }, {
21
+ "expires_date": "2014-11-12 15:15:33 Etc/GMT",
22
+ "expires_date_ms": "1415805333000",
23
+ "expires_date_pst": "2014-11-12 07:15:33 America/Los_Angeles",
24
+ "is_trial_period": "false",
25
+ "original_purchase_date": "2014-11-12 15:08:34 Etc/GMT",
26
+ "original_purchase_date_ms": "1415804914000",
27
+ "original_purchase_date_pst": "2014-11-12 07:08:34 America/Los_Angeles",
28
+ "original_transaction_id": "1000000131413546",
29
+ "product_id": "com.musteus.musteus.subscription.month",
30
+ "purchase_date": "2014-11-12 15:25:30 Etc/GMT",
31
+ "purchase_date_ms": "1415805930044",
32
+ "purchase_date_pst": "2014-11-12 07:25:30 America/Los_Angeles",
33
+ "quantity": "1",
34
+ "transaction_id": "1000000131413602",
35
+ "web_order_line_item_id": "1000000028817187"
36
+ }, {
37
+ "expires_date": "2014-11-12 15:20:33 Etc/GMT",
38
+ "expires_date_ms": "1415805633000",
39
+ "expires_date_pst": "2014-11-12 07:20:33 America/Los_Angeles",
40
+ "is_trial_period": "false",
41
+ "original_purchase_date": "2014-11-12 15:14:15 Etc/GMT",
42
+ "original_purchase_date_ms": "1415805255000",
43
+ "original_purchase_date_pst": "2014-11-12 07:14:15 America/Los_Angeles",
44
+ "original_transaction_id": "1000000131413546",
45
+ "product_id": "com.musteus.musteus.subscription.month",
46
+ "purchase_date": "2014-11-12 15:25:30 Etc/GMT",
47
+ "purchase_date_ms": "1415805930044",
48
+ "purchase_date_pst": "2014-11-12 07:25:30 America/Los_Angeles",
49
+ "quantity": "1",
50
+ "transaction_id": "1000000131414118",
51
+ "web_order_line_item_id": "1000000028817195"
52
+ }, {
53
+ "expires_date": "2014-11-12 15:25:33 Etc/GMT",
54
+ "expires_date_ms": "1415805933000",
55
+ "expires_date_pst": "2014-11-12 07:25:33 America/Los_Angeles",
56
+ "is_trial_period": "false",
57
+ "original_purchase_date": "2014-11-12 15:18:35 Etc/GMT",
58
+ "original_purchase_date_ms": "1415805515000",
59
+ "original_purchase_date_pst": "2014-11-12 07:18:35 America/Los_Angeles",
60
+ "original_transaction_id": "1000000131413546",
61
+ "product_id": "com.musteus.musteus.subscription.month",
62
+ "purchase_date": "2014-11-12 15:25:30 Etc/GMT",
63
+ "purchase_date_ms": "1415805930044",
64
+ "purchase_date_pst": "2014-11-12 07:25:30 America/Los_Angeles",
65
+ "quantity": "1",
66
+ "transaction_id": "1000000131415612",
67
+ "web_order_line_item_id": "1000000028817228"
68
+ }, {
69
+ "expires_date": "2014-11-12 15:30:33 Etc/GMT",
70
+ "expires_date_ms": "1415806233000",
71
+ "expires_date_pst": "2014-11-12 07:30:33 America/Los_Angeles",
72
+ "is_trial_period": "false",
73
+ "original_purchase_date": "2014-11-12 15:23:35 Etc/GMT",
74
+ "original_purchase_date_ms": "1415805815000",
75
+ "original_purchase_date_pst": "2014-11-12 07:23:35 America/Los_Angeles",
76
+ "original_transaction_id": "1000000131413546",
77
+ "product_id": "com.musteus.musteus.subscription.month",
78
+ "purchase_date": "2014-11-12 15:25:30 Etc/GMT",
79
+ "purchase_date_ms": "1415805930044",
80
+ "purchase_date_pst": "2014-11-12 07:25:30 America/Los_Angeles",
81
+ "quantity": "1",
82
+ "transaction_id": "1000000131415863",
83
+ "web_order_line_item_id": "1000000028817256"
84
+ }],
85
+ "receipt": {
86
+ "adam_id": 0,
87
+ "app_item_id": 0,
88
+ "application_version": "1.0",
89
+ "bundle_id": "com.musteus.musteus",
90
+ "download_id": 0,
91
+ "in_app": [{
92
+ "expires_date": "2014-11-12 15:15:33 Etc/GMT",
93
+ "expires_date_ms": "1415805333000",
94
+ "expires_date_pst": "2014-11-12 07:15:33 America/Los_Angeles",
95
+ "is_trial_period": "false",
96
+ "original_purchase_date": "2014-11-12 15:08:34 Etc/GMT",
97
+ "original_purchase_date_ms": "1415804914000",
98
+ "original_purchase_date_pst": "2014-11-12 07:08:34 America/Los_Angeles",
99
+ "original_transaction_id": "1000000131413546",
100
+ "product_id": "com.musteus.musteus.subscription.month",
101
+ "purchase_date": "2014-11-12 15:09:10 Etc/GMT",
102
+ "purchase_date_ms": "1415804950000",
103
+ "purchase_date_pst": "2014-11-12 07:09:10 America/Los_Angeles",
104
+ "quantity": "1",
105
+ "transaction_id": "1000000131413602",
106
+ "web_order_line_item_id": "1000000028817187"
107
+ }, {
108
+ "expires_date": "2014-11-12 15:10:33 Etc/GMT",
109
+ "expires_date_ms": "1415805033000",
110
+ "expires_date_pst": "2014-11-12 07:10:33 America/Los_Angeles",
111
+ "is_trial_period": "false",
112
+ "original_purchase_date": "2014-11-12 15:07:34 Etc/GMT",
113
+ "original_purchase_date_ms": "1415804854000",
114
+ "original_purchase_date_pst": "2014-11-12 07:07:34 America/Los_Angeles",
115
+ "original_transaction_id": "1000000131413546",
116
+ "product_id": "com.musteus.musteus.subscription.month",
117
+ "purchase_date": "2014-11-12 15:09:10 Etc/GMT",
118
+ "purchase_date_ms": "1415804950000",
119
+ "purchase_date_pst": "2014-11-12 07:09:10 America/Los_Angeles",
120
+ "quantity": "1",
121
+ "transaction_id": "1000000131413546",
122
+ "web_order_line_item_id": "1000000028817186"
123
+ }],
124
+ "original_application_version": "1.0",
125
+ "original_purchase_date": "2013-08-01 07:00:00 Etc/GMT",
126
+ "original_purchase_date_ms": "1375340400000",
127
+ "original_purchase_date_pst": "2013-08-01 00:00:00 America/Los_Angeles",
128
+ "receipt_type": "ProductionSandbox",
129
+ "request_date": "2014-11-12 15:25:30 Etc/GMT",
130
+ "request_date_ms": "1415805930053",
131
+ "request_date_pst": "2014-11-12 07:25:30 America/Los_Angeles",
132
+ "version_external_identifier": 0
133
+ },
134
+ "status": 0
135
+ }
@@ -0,0 +1,2 @@
1
+ {"receipt":{"original_purchase_date_pst":"2012-10-11 07:45:40 America/Los_Angeles", "unique_identifier":"4d69cc362c5c58ce62da68ee43721ea670907bad", "original_transaction_id":"1000000057005439", "expires_date":"1350157508197", "transaction_id":"1000000055076747", "quantity":"1", "product_id":"com.notkeepingitreal.fizzbuzz.subscription.autorenew1m", "original_purchase_date_ms":"1349966740000", "bid":"com.notkeepingitreal.fizzbuzz", "web_order_line_item_id":"1000000026553289", "bvrs":"1.0", "expires_date_formatted":"2012-10-13 19:45:08 Etc/GMT", "purchase_date":"2012-10-13 19:40:08 Etc/GMT", "purchase_date_ms":"1350157208197", "expires_date_formatted_pst":"2012-10-13 12:45:08 America/Los_Angeles", "purchase_date_pst":"2012-10-13 12:40:08 America/Los_Angeles", "original_purchase_date":"2012-10-11 14:45:40 Etc/GMT", "item_id":"570504929"}, "latest_receipt_info":{"original_purchase_date_pst":"2012-10-11 07:45:40 America/Los_Angeles", "unique_identifier":"4d79cc562c5c58ce62da68ee43721ea670907bad", "original_transaction_id":"1000000057005439", "expires_date":"1350157808000", "transaction_id":"1000000052076747", "quantity":"1", "product_id":"com.notkeepingitreal.fizzbuzz.subscription.autorenew1m", "original_purchase_date_ms":"1349966740000", "bid":"com.notkeepingitreal.fizzbuzz", "web_order_line_item_id":"1000000027293289", "bvrs":"1.0", "expires_date_formatted":"2012-10-13 19:50:08 Etc/GMT", "purchase_date":"2012-10-13 19:40:08 Etc/GMT", "purchase_date_ms":"1350157208000", "expires_date_formatted_pst":"2012-10-13 12:50:08 America/Los_Angeles", "purchase_date_pst":"2012-10-13 12:40:08 America/Los_Angeles", "original_purchase_date":"2012-10-11 14:45:40 Etc/GMT", "item_id":"570504929"}, "status":0, "latest_receipt":"junk="}
2
+
@@ -0,0 +1,2 @@
1
+ {"receipt":{"original_purchase_date_pst":"2012-10-11 07:45:40 America/Los_Angeles", "unique_identifier":"4d69cc362c5c58ce62da68ee43721ea670907bad", "original_transaction_id":"1000000057005439", "expires_date":"1350157508197", "transaction_id":"1000000055076747", "quantity":"1", "product_id":"com.notkeepingitreal.fizzbuzz.subscription.autorenew1m", "original_purchase_date_ms":"1349966740000", "bid":"com.notkeepingitreal.fizzbuzz", "web_order_line_item_id":"1000000026553289", "bvrs":"1.0", "expires_date_formatted":"2012-10-13 19:45:08 Etc/GMT", "purchase_date":"2012-10-13 19:40:08 Etc/GMT", "purchase_date_ms":"1350157208197", "expires_date_formatted_pst":"2012-10-13 12:45:08 America/Los_Angeles", "purchase_date_pst":"2012-10-13 12:40:08 America/Los_Angeles", "original_purchase_date":"2012-10-11 14:45:40 Etc/GMT", "item_id":"570504929"}, "latest_receipt_info":{"original_purchase_date_pst":"2012-10-11 07:45:40 America/Los_Angeles", "unique_identifier":"4d79cc562c5c58ce62da68ee43721ea670907bad", "original_transaction_id":"1000000057005439", "expires_date":"1350157808000", "transaction_id":"1000000052076747", "quantity":"1", "product_id":"com.notkeepingitreal.fizzbuzz.subscription.autorenew1m", "original_purchase_date_ms":"1349966740000", "bid":"com.notkeepingitreal.fizzbuzz", "web_order_line_item_id":"1000000027293289", "bvrs":"1.0", "expires_date_formatted":"2012-10-13 19:50:08 Etc/GMT", "purchase_date":"2012-10-13 19:40:08 Etc/GMT", "purchase_date_ms":"1350157208000", "expires_date_formatted_pst":"2012-10-13 12:50:08 America/Los_Angeles", "purchase_date_pst":"2012-10-13 12:40:08 America/Los_Angeles", "original_purchase_date":"2012-10-11 14:45:40 Etc/GMT", "item_id":"570504929"}, "status":21006, "latest_receipt":"junk="}
2
+
@@ -0,0 +1 @@
1
+ {"status":21002, "exception":"java.lang.IllegalArgumentException: propertyListFromString parsed an object, but there's still more text in the string. A plist should contain only one top-level object. Line number: 6, column: 1."}
@@ -0,0 +1 @@
1
+ {"status":21005}
@@ -0,0 +1 @@
1
+ {"receipt":{"item_id":"420862234", "original_transaction_id":"1000000001479608", "bvrs":"1.0", "product_id":"com.cerego.iknow.30d", "purchase_date":"2011-02-17 06:20:57 Etc/GMT", "quantity":"1", "bid":"com.cerego.iknow", "original_purchase_date":"2011-02-17 06:20:57 Etc/GMT", "transaction_id":"1000000001500000"}, "status":21007}
@@ -0,0 +1 @@
1
+ {"receipt":{"item_id":"420862234", "original_transaction_id":"1000000001479608", "bvrs":"1.0", "product_id":"com.cerego.iknow.30d", "purchase_date":"2011-02-17 06:20:57 Etc/GMT", "quantity":"1", "bid":"com.cerego.iknow", "original_purchase_date":"2011-02-17 06:20:57 Etc/GMT", "transaction_id":"1000000001479608"}, "status":0}
@@ -0,0 +1,38 @@
1
+ {"status":0,
2
+ "environment":"Sandbox",
3
+ "receipt":{
4
+ "receipt_type":"ProductionSandbox",
5
+ "adam_id":0,
6
+ "bundle_id":"com.tekkinnovations.fars",
7
+ "application_version":"1.80",
8
+ "download_id":0,
9
+ "request_date":"2013-11-26 14:49:09 Etc/GMT",
10
+ "request_date_ms":"1385477349878",
11
+ "request_date_pst":"2013-11-26 06:49:09 America/Los_Angeles",
12
+ "original_purchase_date":"2013-08-01 07:00:00 Etc/GMT",
13
+ "original_purchase_date_ms":"1375340400000",
14
+ "original_purchase_date_pst":"2013-08-01 00:00:00 America/Los_Angeles",
15
+ "original_application_version":"1.0",
16
+ "in_app":[{"quantity":"1",
17
+ "product_id":"com.tekkinnovations.fars.subscription.6.months",
18
+ "transaction_id":"1000000091176126",
19
+ "original_transaction_id":"1000000091176126",
20
+ "purchase_date":"2013-11-26 05:58:48 Etc/GMT",
21
+ "purchase_date_ms":"1385445528000",
22
+ "purchase_date_pst":"2013-11-25 21:58:48 America/Los_Angeles",
23
+ "original_purchase_date":"2013-10-24 04:55:56 Etc/GMT",
24
+ "original_purchase_date_ms":"1382590556000",
25
+ "original_purchase_date_pst":"2013-10-23 21:55:56 America/Los_Angeles",
26
+ "is_trial_period":"false"},
27
+ {"quantity":"1",
28
+ "product_id":"com.tekkinnovations.fars.subscription.3.months",
29
+ "transaction_id":"1000000091221097",
30
+ "original_transaction_id":"1000000091221097",
31
+ "purchase_date":"2013-11-26 05:58:48 Etc/GMT",
32
+ "purchase_date_ms":"1385445528000",
33
+ "purchase_date_pst":"2013-11-25 21:58:48 America/Los_Angeles",
34
+ "original_purchase_date":"2013-10-24 09:40:22 Etc/GMT",
35
+ "original_purchase_date_ms":"1382607622000",
36
+ "original_purchase_date_pst":"2013-10-24 02:40:22 America/Los_Angeles",
37
+ "is_trial_period":"false"}
38
+ ]}}
@@ -0,0 +1,25 @@
1
+ require 'fakeweb'
2
+
3
+ module FakeJsonHelper
4
+
5
+ def fake_json(expected, options = {})
6
+ FakeWeb.register_uri(
7
+ :post,
8
+ Itunes.endpoint,
9
+ options.merge(
10
+ :body => File.read(File.join(File.dirname(__FILE__), '../fake_json', "#{expected}.json"))
11
+ )
12
+ )
13
+ end
14
+
15
+ def post_to(endpoint)
16
+ raise_error(
17
+ FakeWeb::NetConnectNotAllowedError,
18
+ "Real HTTP connections are disabled. Unregistered request: POST #{endpoint}"
19
+ )
20
+ end
21
+
22
+ end
23
+
24
+ FakeWeb.allow_net_connect = false
25
+ include FakeJsonHelper
@@ -0,0 +1,252 @@
1
+ require 'spec_helper'
2
+
3
+ describe Itunes::Receipt do
4
+
5
+ describe '.verify!' do
6
+ it 'should support sandbox mode' do
7
+ sandbox_mode do
8
+ expect do
9
+ Itunes::Receipt.verify! 'receipt-data'
10
+ end.to post_to Itunes::ENDPOINT[:sandbox]
11
+ end
12
+ end
13
+
14
+ it 'should not pass along shared secret if not set' do
15
+ fake_json(:invalid)
16
+ Itunes.shared_secret = nil
17
+ RestClient.should_receive(:post).with(Itunes.endpoint, {:'receipt-data' => 'receipt-data'}.to_json).and_return("{}")
18
+ expect do
19
+ Itunes::Receipt.verify! 'receipt-data'
20
+ end.to raise_error Itunes::Receipt::VerificationFailed
21
+ end
22
+
23
+ it 'should pass along shared secret if set' do
24
+ fake_json(:invalid)
25
+ Itunes.shared_secret = 'hey'
26
+ RestClient.should_receive(:post).with(Itunes.endpoint, {:'receipt-data' => 'receipt-data', :password => 'hey'}.to_json).and_return("{}")
27
+ expect do
28
+ Itunes::Receipt.verify! 'receipt-data'
29
+ end.to raise_error Itunes::Receipt::VerificationFailed
30
+ end
31
+
32
+ context 'when invalid' do
33
+ before do
34
+ fake_json :invalid
35
+ end
36
+
37
+ it 'should raise VerificationFailed' do
38
+ expect do
39
+ Itunes::Receipt.verify! 'invalid'
40
+ end.to raise_error Itunes::Receipt::VerificationFailed
41
+ end
42
+
43
+ context 'due to a sandbox receipt reply' do
44
+ before do
45
+ fake_json :sandboxed
46
+ sandbox_mode do
47
+ fake_json :valid
48
+ end
49
+ end
50
+
51
+ context 'when sandbox receipt accepted explicitly' do
52
+ it 'should try and verify the receipt against the sandbox ' do
53
+ receipt = Itunes::Receipt.verify! 'sandboxed', :allow_sandbox_receipt
54
+ receipt.should be_instance_of Itunes::Receipt
55
+ receipt.transaction_id.should == '1000000001479608'
56
+ receipt.itunes_env.should == :sandbox
57
+ receipt.sandbox?.should eq true
58
+ end
59
+ end
60
+
61
+ context 'otherwise' do
62
+ it 'should raise SandboxReceiptReceived exception' do
63
+ expect do
64
+ Itunes::Receipt.verify! 'sandboxed'
65
+ end.to raise_error Itunes::Receipt::SandboxReceiptReceived
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ context 'when valid' do
72
+ before do
73
+ fake_json :valid
74
+ end
75
+
76
+ it 'should not be an application receipt' do
77
+ receipt = Itunes::Receipt.verify! 'valid_application'
78
+ receipt.application_receipt?.should == false
79
+ end
80
+
81
+ it 'should return valid Receipt instance' do
82
+ receipt = Itunes::Receipt.verify! 'valid'
83
+ receipt.should be_instance_of Itunes::Receipt
84
+ receipt.quantity == 1
85
+ receipt.product_id.should == 'com.cerego.iknow.30d'
86
+ receipt.transaction_id.should == '1000000001479608'
87
+ receipt.purchase_date.should == Time.utc(2011, 2, 17, 6, 20, 57)
88
+ receipt.bid.should == 'com.cerego.iknow'
89
+ receipt.bvrs.should == '1.0'
90
+ receipt.original.quantity.should be_nil
91
+ receipt.original.transaction_id.should == '1000000001479608'
92
+ receipt.original.purchase_date.should == Time.utc(2011, 2, 17, 6, 20, 57)
93
+ receipt.expires_date.should be_nil
94
+ receipt.receipt_data.should be_nil
95
+ receipt.itunes_env.should == :production
96
+
97
+ # Those attributes are not returned from iTunes Connect Sandbox
98
+ receipt.app_item_id.should be_nil
99
+ receipt.version_external_identifier.should be_nil
100
+ end
101
+ end
102
+
103
+ context 'when application receipt' do
104
+ before do
105
+ fake_json :valid_application
106
+ end
107
+
108
+ it 'should be an application receipt' do
109
+ receipt = Itunes::Receipt.verify! 'valid_application'
110
+ receipt.application_receipt?.should == true
111
+ end
112
+
113
+ it 'should return valid Receipt instance' do
114
+ receipt = Itunes::Receipt.verify! 'valid_application'
115
+ receipt.bundle_id.should == 'com.tekkinnovations.fars'
116
+ receipt.application_version.should == '1.80'
117
+ receipt.in_app.should be_instance_of Array
118
+
119
+ receipt.in_app[0].should be_instance_of Itunes::Receipt
120
+ receipt.in_app[0].quantity.should == 1
121
+ receipt.in_app[0].product_id.should == "com.tekkinnovations.fars.subscription.6.months"
122
+ receipt.in_app[0].transaction_id.should == "1000000091176126"
123
+ receipt.in_app[0].purchase_date.should == Time.utc(2013, 11, 26, 5, 58, 48)
124
+ receipt.in_app[0].original.purchase_date.should == Time.utc(2013, 10, 24, 4, 55, 56)
125
+
126
+ receipt.in_app[1].should be_instance_of Itunes::Receipt
127
+ receipt.in_app[1].quantity.should == 1
128
+ receipt.in_app[1].product_id.should == "com.tekkinnovations.fars.subscription.3.months"
129
+ receipt.in_app[1].transaction_id.should == "1000000091221097"
130
+ receipt.in_app[1].purchase_date.should == Time.utc(2013, 11, 26, 5, 58, 48)
131
+ receipt.in_app[1].original.purchase_date.should == Time.utc(2013, 10, 24, 9, 40, 22)
132
+
133
+ receipt.original.quantity.should be_nil
134
+ receipt.original.transaction_id.should be_nil
135
+ receipt.original.purchase_date.should == Time.utc(2013, 8, 1, 7, 00, 00)
136
+ receipt.original.application_version.should == '1.0'
137
+
138
+ receipt.should be_instance_of Itunes::Receipt
139
+ receipt.quantity.should be_nil
140
+ receipt.product_id.should be_nil
141
+ receipt.transaction_id.should be_nil
142
+ receipt.purchase_date.should be_nil
143
+ receipt.bid.should be_nil
144
+ receipt.bvrs.should be_nil
145
+ receipt.expires_date.should be_nil
146
+ receipt.receipt_data.should be_nil
147
+ receipt.itunes_env.should == :production
148
+
149
+ # Those attributes are not returned from iTunes Connect Sandbox
150
+ receipt.app_item_id.should be_nil
151
+ receipt.version_external_identifier.should be_nil
152
+ end
153
+ end
154
+
155
+ context 'when autorenew subscription' do
156
+ before do
157
+ fake_json :autorenew_subscription
158
+ end
159
+
160
+ it 'should return valid Receipt instance for autorenew subscription' do
161
+ original_transaction_id = '1000000057005439'
162
+ original_purchase_date = Time.utc(2012, 10, 11, 14, 45, 40)
163
+ receipt = Itunes::Receipt.verify! 'autorenew_subscription'
164
+ receipt.should be_instance_of Itunes::Receipt
165
+ receipt.quantity == 1
166
+ receipt.product_id.should == 'com.notkeepingitreal.fizzbuzz.subscription.autorenew1m'
167
+ receipt.transaction_id.should == '1000000055076747'
168
+ receipt.purchase_date.should == Time.utc(2012, 10, 13, 19, 40, 8)
169
+ receipt.bid.should == 'com.notkeepingitreal.fizzbuzz'
170
+ receipt.bvrs.should == '1.0'
171
+ receipt.original.quantity.should be_nil
172
+ receipt.original.transaction_id.should == original_transaction_id
173
+ receipt.original.purchase_date.should == original_purchase_date
174
+ receipt.expires_date.should == Time.utc(2012, 10, 13, 19, 45, 8)
175
+ receipt.receipt_data.should be_nil
176
+
177
+ # Those attributes are not returned from iTunes Connect Sandbox
178
+ receipt.app_item_id.should be_nil
179
+ receipt.version_external_identifier.should be_nil
180
+
181
+ latest = receipt.latest
182
+ latest.should be_instance_of Itunes::Receipt
183
+ latest.quantity == 1
184
+ latest.product_id.should == 'com.notkeepingitreal.fizzbuzz.subscription.autorenew1m'
185
+ latest.transaction_id.should == '1000000052076747'
186
+ latest.purchase_date.should == Time.utc(2012, 10, 13, 19, 40, 8)
187
+ latest.expires_date.should == Time.utc(2012, 10, 13, 19, 50, 8) # five minutes after the "old" receipt
188
+ latest.bid.should == 'com.notkeepingitreal.fizzbuzz'
189
+ latest.bvrs.should == '1.0'
190
+ latest.original.quantity.should be_nil
191
+ latest.original.transaction_id.should == original_transaction_id
192
+ latest.original.purchase_date.should == original_purchase_date
193
+ latest.receipt_data.should == 'junk='
194
+
195
+ # Those attributes are not returned from iTunes Connect Sandbox
196
+ latest.app_item_id.should be_nil
197
+ latest.version_external_identifier.should be_nil
198
+ end
199
+ end
200
+
201
+ context 'when expired autorenew subscription' do
202
+ before do
203
+ fake_json :autorenew_subscription_expired
204
+ end
205
+
206
+ it 'should raise ExpiredReceiptReceived exception' do
207
+ expect do
208
+ Itunes::Receipt.verify! 'autorenew_subscription_expired'
209
+ end.to raise_error Itunes::Receipt::ExpiredReceiptReceived do |e|
210
+ e.receipt.should_not be_nil
211
+ end
212
+ end
213
+
214
+ end
215
+
216
+ context 'when offline' do
217
+ before do
218
+ fake_json :offline
219
+ end
220
+
221
+ it 'should raise ReceiptServerOffline exception' do
222
+ expect do
223
+ Itunes::Receipt.verify! 'offline'
224
+ end.to raise_error Itunes::Receipt::ReceiptServerOffline
225
+ end
226
+ end
227
+
228
+ describe '#latest' do
229
+ let(:receipt) { Itunes::Receipt.verify! 'receipt-data' }
230
+ subject { receipt.latest }
231
+
232
+ context 'when latest_receipt_info is a Hash' do
233
+ before do
234
+ fake_json :autorenew_subscription
235
+ end
236
+ it { should be_a Itunes::Receipt }
237
+ end
238
+
239
+ context 'when latest_receipt_info is an Array' do
240
+ before do
241
+ fake_json :array_of_latest_receipt_info
242
+ end
243
+ it { should be_a Array }
244
+ it 'should include only Itunes::Receipt' do
245
+ receipt.latest.each do |element|
246
+ element.should be_a Itunes::Receipt
247
+ end
248
+ end
249
+ end
250
+ end
251
+ end
252
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Itunes do
4
+
5
+ describe 'the module' do
6
+ before do
7
+ Itunes.shared_secret = nil
8
+ end
9
+
10
+ context 'sandbox' do
11
+ it 'should be production by default' do
12
+ Itunes.sandbox?.should == false
13
+ end
14
+
15
+ it 'should be settable' do
16
+ Itunes.sandbox!
17
+ Itunes.sandbox?.should == true
18
+ end
19
+ end
20
+
21
+ context 'shared_secret' do
22
+ it 'should allow setting' do
23
+ Itunes.shared_secret.should be_nil
24
+ Itunes.shared_secret = 'hey'
25
+ Itunes.shared_secret.should == 'hey'
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ require 'simplecov'
2
+
3
+ SimpleCov.start do
4
+ add_filter 'spec'
5
+ end
6
+
7
+ require 'rspec'
8
+ require 'itunes/receipt'
9
+ require 'helpers/fake_json_helper'
10
+
11
+ def sandbox_mode(&block)
12
+ Itunes.sandbox!
13
+ yield
14
+ ensure
15
+ Itunes.sandbox = false
16
+ end
metadata ADDED
@@ -0,0 +1,191 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: suhovius-itunes-receipt
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.1
5
+ platform: ruby
6
+ authors:
7
+ - nov matake
8
+ - suhovius
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2016-04-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 1.4.3
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 1.4.3
28
+ - !ruby/object:Gem::Dependency
29
+ name: restclient_with_cert
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: activesupport
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '2.3'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '2.3'
56
+ - !ruby/object:Gem::Dependency
57
+ name: i18n
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rake
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0.8'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0.8'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '2'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '2'
98
+ - !ruby/object:Gem::Dependency
99
+ name: fakeweb
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 1.3.0
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: 1.3.0
112
+ - !ruby/object:Gem::Dependency
113
+ name: simplecov
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: Handle iTunes In App Purchase Receipt Verification
127
+ email: nov@matake.jp
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".rspec"
134
+ - ".travis.yml"
135
+ - Gemfile
136
+ - LICENSE
137
+ - README.rdoc
138
+ - Rakefile
139
+ - VERSION
140
+ - itunes-receipt.gemspec
141
+ - lib/itunes.rb
142
+ - lib/itunes/receipt.rb
143
+ - spec/fake_json/array_of_latest_receipt_info.json
144
+ - spec/fake_json/autorenew_subscription.json
145
+ - spec/fake_json/autorenew_subscription_expired.json
146
+ - spec/fake_json/invalid.json
147
+ - spec/fake_json/offline.json
148
+ - spec/fake_json/sandboxed.json
149
+ - spec/fake_json/valid.json
150
+ - spec/fake_json/valid_application.json
151
+ - spec/helpers/fake_json_helper.rb
152
+ - spec/itunes/receipt_spec.rb
153
+ - spec/itunes_spec.rb
154
+ - spec/spec_helper.rb
155
+ homepage: https://github.com/suhovius/itunes-receipt
156
+ licenses: []
157
+ metadata: {}
158
+ post_install_message:
159
+ rdoc_options: []
160
+ require_paths:
161
+ - lib
162
+ required_ruby_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ required_rubygems_version: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ requirements: []
173
+ rubyforge_project:
174
+ rubygems_version: 2.4.3
175
+ signing_key:
176
+ specification_version: 4
177
+ summary: Handle iTunes In App Purchase Receipt Verification
178
+ test_files:
179
+ - spec/fake_json/array_of_latest_receipt_info.json
180
+ - spec/fake_json/autorenew_subscription.json
181
+ - spec/fake_json/autorenew_subscription_expired.json
182
+ - spec/fake_json/invalid.json
183
+ - spec/fake_json/offline.json
184
+ - spec/fake_json/sandboxed.json
185
+ - spec/fake_json/valid.json
186
+ - spec/fake_json/valid_application.json
187
+ - spec/helpers/fake_json_helper.rb
188
+ - spec/itunes/receipt_spec.rb
189
+ - spec/itunes_spec.rb
190
+ - spec/spec_helper.rb
191
+ has_rdoc: