fattaholmanan-venice 0.2.0

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: 49492d7429cb9a0d437ef24f1b5c5187e33ad084
4
+ data.tar.gz: 2831c7853aebe0a0b6713ada36c257698fba8b00
5
+ SHA512:
6
+ metadata.gz: b0def4411ebf45599b39b61c75f1822a5dba44be7914b3eb495201fc5dd91c89cb0c01f01de1d964dc3d8e20d67134e05efc74c753fb084b7be21fab1eaf5b55
7
+ data.tar.gz: 37a625cc05d06879bbcfc4b3e16424f9ad79b5e1d48eb072a0e1b47cdb71611ef8e42567e77d181427e64dc805dbcd36db0398379191edbea49a8224989f5e5d
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2013 Mattt Thompson (http://mattt.me/)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ ![Venice](https://raw.github.com/mattt/nomad-cli.com/assets/venice-banner.png)
2
+
3
+ Venice is a simple gem for verifying Apple In-App Purchase receipts, and retrieving the information associated with receipt data.
4
+
5
+ There are two reasons why you should verify in-app purchase receipts on the server: First, it allows you to keep your own records of past purchases, which is useful for up-to-the-minute metrics and historical analysis. Second, server-side verification over SSL is the most reliable way to determine the authenticity of purchasing records.
6
+
7
+ See Apple's [In-App Purchase Programming Guide](http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/StoreKitGuide/VerifyingStoreReceipts/VerifyingStoreReceipts.html) for additional information.
8
+
9
+ > Venice is named for [Venice, Italy](http://en.wikipedia.org/wiki/Venice,_Italy)—or more specifically, Shakespeare's [_The Merchant of Venice_](http://en.wikipedia.org/wiki/The_Merchant_of_Venice).
10
+ > It's part of a series of world-class command-line utilities for iOS development, which includes [Cupertino](https://github.com/mattt/cupertino) (Apple Dev Center management), [Shenzhen](https://github.com/mattt/shenzhen) (Building & Distribution), [Houston](https://github.com/mattt/houston) (Push Notifications), and [Dubai](https://github.com/mattt/dubai) (Passbook pass generation).
11
+
12
+ ## Installation
13
+
14
+ $ gem install venice
15
+
16
+ ## Usage
17
+
18
+ ```ruby
19
+ require 'venice'
20
+
21
+ data = "(Base64-Encoded Receipt Data)"
22
+ if receipt = Venice::Receipt.verify(data)
23
+ p receipt.to_h
24
+ end
25
+ ```
26
+
27
+ ## Command Line Interface
28
+
29
+ Venice also comes with the `iap` binary, which provides a convenient way to verify receipts from the command line.
30
+
31
+
32
+ $ iap verify /path/to/receipt
33
+
34
+ +--------------------------------+------------------------------------+
35
+ | Receipt |
36
+ +--------------------------------+------------------------------------+
37
+ | adam_id | 664753504 |
38
+ | application_version | 123 |
39
+ | bundle_id | com.example.product |
40
+ | download_id | 30000000000005 |
41
+ | expires_at | |
42
+ | latest_receipt | |
43
+ | original_application_version | 123 |
44
+ | original_purchase_date | Fri, 07 Mar 2014 20:59:24 GMT |
45
+ | receipt_type | Production |
46
+ | requested_at | Mon, 23 Jun 2014 17:59:38 GMT |
47
+ +--------------------------------+------------------------------------+
48
+ | in_app | 1 |
49
+ | - app_item_id | |
50
+ | - cancellation_at | |
51
+ | - expires_at | |
52
+ | - original_purchase_date | |
53
+ | - original_transaction_id | 1000000000000001 |
54
+ | - product_id | com.example.product |
55
+ | - purchase_date | |
56
+ | - quantity | 1 |
57
+ | - transaction_id | 1000000000000001 |
58
+ | - version_external_identifier | |
59
+ +--------------------------------+------------------------------------+
60
+
61
+
62
+ ## Contact
63
+
64
+ Mattt Thompson
65
+
66
+ - http://github.com/mattt
67
+ - http://twitter.com/mattt
68
+ - m@mattt.me
69
+
70
+ ## License
71
+
72
+ Venice is available under the MIT license. See the LICENSE file for more info.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler/setup'
2
+
3
+ gemspec = eval(File.read("venice.gemspec"))
4
+
5
+ task :build => "#{gemspec.full_name}.gem"
6
+
7
+ file "#{gemspec.full_name}.gem" => gemspec.files + ["venice.gemspec"] do
8
+ system "gem build venice.gemspec"
9
+ end
data/bin/iap ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'venice'
4
+
5
+
6
+ require 'commander/import'
7
+ require 'terminal-table'
8
+
9
+
10
+ HighLine.track_eof = false # Fix for built-in Ruby
11
+ Signal.trap("INT") {} # Suppress backtrace when exiting command
12
+
13
+ program :version, Venice::VERSION
14
+ program :description, 'A command-line interface for verifying Apple In-App Purchase receipts'
15
+
16
+ program :help, 'Author', 'Mattt Thompson <m@mattt.me>'
17
+ program :help, 'Website', 'https://github.com/mattt'
18
+ program :help_formatter, :compact
19
+
20
+ default_command :help
21
+
22
+ command :verify do |c|
23
+ c.syntax = 'iap verify RECEIPT'
24
+ c.summary = 'Verifies an In-App Purchase Receipt'
25
+ c.description = ''
26
+ c.option '-S', '--[no-]sandbox', 'Use sandbox verification webservice'
27
+ c.option '-p', '--secret SECRET', 'Use a shared secret for auto-renewable subscription receipts'
28
+
29
+ c.example 'description', 'iap verify /path/to/receipt [--secret shared_secret]'
30
+
31
+ c.action do |args, options|
32
+ say_error "Missing receipt argument" and abort unless file = args.first
33
+ say_error "Receipt file does not exist" unless File.exist?(file)
34
+
35
+ client = options.sandbox ? Venice::Client.development : Venice::Client.production
36
+ client.shared_secret = options.secret if options.secret
37
+
38
+ begin
39
+ receipt = client.verify!(File.read(file))
40
+
41
+ table = Terminal::Table.new :title => "Receipt" do |t|
42
+ hash = receipt.to_h
43
+ hash.keys.sort.each do |key|
44
+ next if key == :in_app
45
+ t << [key, hash[key]]
46
+ end
47
+
48
+ if hash[:in_app]
49
+ index = 0
50
+ hash[:in_app].each do |iap|
51
+ index += 1
52
+ t << :separator
53
+ t << [:in_app, index]
54
+ iap.keys.sort.each do |key|
55
+ t << [" - #{key}", iap[key]]
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ puts table
62
+
63
+ rescue => error
64
+ say_error error.message and abort
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "venice/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "fattaholmanan-venice"
7
+ s.authors = ["Ali Fattaholmanan"]
8
+ s.email = "fattah@pichak.co"
9
+ s.license = "MIT"
10
+ s.homepage = "http://nomad-cli.com"
11
+ s.version = Venice::VERSION
12
+ s.platform = Gem::Platform::RUBY
13
+ s.summary = "iTunes In-App Purchase Receipt Verification"
14
+ s.description = ""
15
+
16
+ s.add_dependency "json"
17
+ s.add_dependency "commander", "~> 4.1"
18
+ s.add_dependency "terminal-table", "~> 1.4"
19
+
20
+ s.add_development_dependency "rspec", "~> 2.99.0"
21
+ s.add_development_dependency "rake"
22
+ s.add_development_dependency "simplecov"
23
+ s.add_development_dependency "pry-byebug"
24
+
25
+ s.files = Dir["./**/*"].reject { |file| file =~ /\.\/(bin|log|pkg|script|spec|test|vendor)/ }
26
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
27
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
28
+ s.require_paths = ["lib"]
29
+ end
@@ -0,0 +1,74 @@
1
+ require 'json'
2
+ require 'net/https'
3
+ require 'uri'
4
+
5
+ module Venice
6
+ ITUNES_PRODUCTION_RECEIPT_VERIFICATION_ENDPOINT = "https://buy.itunes.apple.com/verifyReceipt"
7
+ ITUNES_DEVELOPMENT_RECEIPT_VERIFICATION_ENDPOINT = "https://sandbox.itunes.apple.com/verifyReceipt"
8
+
9
+ class Client
10
+ attr_accessor :verification_url
11
+ attr_writer :shared_secret
12
+
13
+ class << self
14
+ def development
15
+ client = self.new
16
+ client.verification_url = ITUNES_DEVELOPMENT_RECEIPT_VERIFICATION_ENDPOINT
17
+ client
18
+ end
19
+
20
+ def production
21
+ client = self.new
22
+ client.verification_url = ITUNES_PRODUCTION_RECEIPT_VERIFICATION_ENDPOINT
23
+ client
24
+ end
25
+ end
26
+
27
+ def initialize
28
+ @verification_url = ENV['IAP_VERIFICATION_ENDPOINT']
29
+ end
30
+
31
+ def verify!(data, options = {})
32
+ @verification_url ||= ITUNES_DEVELOPMENT_RECEIPT_VERIFICATION_ENDPOINT
33
+ @shared_secret = options[:shared_secret]
34
+
35
+ json = json_response_from_verifying_data(data)
36
+ status, receipt_attributes = json['status'].to_i, json['receipt']
37
+
38
+ case status
39
+ when 0, 21006
40
+ attributes = (receipt_attributes || {}).merge({
41
+ 'latest_receipt' => json['latest_receipt'],
42
+ 'latest_receipt_info' => json['latest_receipt_info'],
43
+ })
44
+ Receipt.new(attributes)
45
+ else
46
+ raise Receipt::VerificationError.new(status, receipt_attributes)
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def json_response_from_verifying_data(data)
53
+ parameters = {
54
+ 'receipt-data' => data
55
+ }
56
+
57
+ parameters['password'] = @shared_secret if @shared_secret
58
+
59
+ uri = URI(@verification_url)
60
+ http = Net::HTTP.new(uri.host, uri.port)
61
+ http.use_ssl = true
62
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
63
+
64
+ request = Net::HTTP::Post.new(uri.request_uri)
65
+ request['Accept'] = "application/json"
66
+ request['Content-Type'] = "application/json"
67
+ request.body = parameters.to_json
68
+
69
+ response = http.request(request)
70
+
71
+ JSON.parse(response.body)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,90 @@
1
+ require 'time'
2
+
3
+ module Venice
4
+ class InAppReceipt
5
+ # For detailed explanations on these keys/values, see
6
+ # https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW12
7
+
8
+ # The number of items purchased. This value corresponds to the quantity property of
9
+ # the SKPayment object stored in the transaction’s payment property.
10
+ attr_reader :quantity
11
+
12
+ # The product identifier of the item that was purchased. This value corresponds to
13
+ # the productIdentifier property of the SKPayment object stored in the transaction’s
14
+ # payment property.
15
+ attr_reader :product_id
16
+
17
+ # The transaction identifier of the item that was purchased. This value corresponds
18
+ # to the transaction’s transactionIdentifier property.
19
+ attr_reader :transaction_id
20
+
21
+ # The date and time this transaction occurred. This value corresponds to the
22
+ # transaction’s transactionDate property.
23
+ attr_reader :purchased_at
24
+
25
+ # A string that the App Store uses to uniquely identify the application that created
26
+ # the payment transaction. If your server supports multiple applications, you can use
27
+ # this value to differentiate between them. Applications that are executing in the
28
+ # sandbox do not yet have an app-item-id assigned to them, so this key is missing from
29
+ # receipts created by the sandbox.
30
+ attr_reader :app_item_id
31
+
32
+ # An arbitrary number that uniquely identifies a revision of your application. This key
33
+ # is missing in receipts created by the sandbox.
34
+ attr_reader :version_external_identifier
35
+
36
+ # For a transaction that restores a previous transaction, this is the original receipt
37
+ attr_accessor :original
38
+
39
+ # For auto-renewable subscriptions, returns the date the subscription will expire
40
+ attr_reader :expires_at
41
+
42
+ # For a transaction that was canceled by Apple customer support, the time and date of the cancellation.
43
+ attr_reader :cancellation_at
44
+
45
+
46
+ def initialize(attributes = {})
47
+ @quantity = Integer(attributes['quantity']) if attributes['quantity']
48
+ @product_id = attributes['product_id']
49
+ @transaction_id = attributes['transaction_id']
50
+ @purchased_at = DateTime.parse(attributes['purchase_date']) if attributes['purchase_date']
51
+ @app_item_id = attributes['app_item_id']
52
+ @version_external_identifier = attributes['version_external_identifier']
53
+
54
+ @expires_at = Time.at(attributes['expires_date'].to_i) if attributes['expires_date']
55
+ # cancellation_date is in ms since the Epoch, Time.at expects seconds
56
+ @cancellation_date = Time.at(attributes['cancellation_date'].to_i / 1000) if attributes['cancellation_date']
57
+
58
+ if attributes['original_transaction_id'] || attributes['original_purchase_date']
59
+ original_attributes = {
60
+ 'transaction_id' => attributes['original_transaction_id'],
61
+ 'purchase_date' => attributes['original_purchase_date']
62
+ }
63
+
64
+ self.original = InAppReceipt.new(original_attributes)
65
+ end
66
+
67
+ end
68
+
69
+ def to_hash
70
+ {
71
+ :quantity => @quantity,
72
+ :product_id => @product_id,
73
+ :transaction_id => @transaction_id,
74
+ :purchase_date => (@purchased_at.httpdate rescue nil),
75
+ :original_transaction_id => (@original.transaction_id rescue nil),
76
+ :original_purchase_date => (@original.purchased_at.httpdate rescue nil),
77
+ :app_item_id => @app_item_id,
78
+ :version_external_identifier => @version_external_identifier,
79
+ :expires_at => (@expires_at.httpdate rescue nil),
80
+ :cancellation_at => (@cancellation_at.httpdate rescue nil)
81
+ }
82
+ end
83
+ alias_method :to_h, :to_hash
84
+
85
+ def to_json
86
+ self.to_hash.to_json
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,158 @@
1
+ require 'time'
2
+
3
+ module Venice
4
+ class Receipt
5
+ # For detailed explanations on these keys/values, see
6
+ # https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1
7
+
8
+ # The app’s bundle identifier.
9
+ attr_reader :bundle_id
10
+
11
+ # The app’s version number.
12
+ attr_reader :application_version
13
+
14
+ # The receipt for an in-app purchase.
15
+ attr_reader :in_app
16
+
17
+ # The version of the app that was originally purchased.
18
+ attr_reader :original_application_version
19
+
20
+ # The original purchase date
21
+ attr_reader :original_purchase_date
22
+
23
+ # The date that the app receipt expires.
24
+ attr_reader :expires_at
25
+
26
+ # Non-Documented receipt keys/values
27
+ attr_reader :receipt_type
28
+ attr_reader :adam_id
29
+ attr_reader :download_id
30
+ attr_reader :requested_at
31
+
32
+ # For auto-renewable subscriptions:
33
+ # the 'receipt-data' base64 representation of the last receipt
34
+ # if happened after the current receipt
35
+ attr_accessor :latest_receipt
36
+ # the in_app-transactions part of the last receipt
37
+ attr_accessor :latest_receipt_info
38
+
39
+ def initialize(attributes = {})
40
+ @bundle_id = attributes['bundle_id']
41
+ @application_version = attributes['application_version']
42
+ @original_application_version = attributes['original_application_version']
43
+ if attributes['original_purchase_date']
44
+ @original_purchase_date = DateTime.parse(attributes['original_purchase_date'])
45
+ end
46
+ if attributes['expiration_date']
47
+ @expires_at = Time.at(attributes['expiration_date'].to_i / 1000).to_datetime
48
+ end
49
+
50
+ @receipt_type = attributes['receipt_type']
51
+ @adam_id = attributes['adam_id']
52
+ @download_id = attributes['download_id']
53
+ @requested_at = DateTime.parse(attributes['request_date']) if attributes['request_date']
54
+
55
+ init_iap_receipts(attributes)
56
+ end
57
+
58
+ def init_iap_receipts(attributes)
59
+ @in_app = map_iap_receipts(attributes['in_app'] || [])
60
+ # From Apple docs:
61
+ # > Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions.
62
+ # > The JSON representation of the receipt for the most recent renewal
63
+
64
+ # @latest_receipt_info = map_iap_receipts(attributes['latest_receipt_info'] || [])
65
+ @latest_receipt_info = InAppReceipt.new (attributes['latest_receipt_info']) rescue []
66
+ @latest_receipt = attributes['latest_receipt']
67
+ end
68
+
69
+ def to_hash
70
+ {
71
+ :bundle_id => @bundle_id,
72
+ :application_version => @application_version,
73
+ :original_application_version => @original_application_version,
74
+ :original_purchase_date => (@original_purchase_date.httpdate rescue nil),
75
+ :expires_at => (@expires_at.httpdate rescue nil),
76
+ :receipt_type => @receipt_type,
77
+ :adam_id => @adam_id,
78
+ :download_id => @download_id,
79
+ :requested_at => (@requested_at.httpdate rescue nil),
80
+ :in_app => @in_app.map{|iap| iap.to_h },
81
+ :latest_receipt_info => @latest_receipt_info.map{|iap| iap.to_h },
82
+ :latest_receipt => @latest_receipt,
83
+ }
84
+ end
85
+ alias_method :to_h, :to_hash
86
+
87
+ def to_json
88
+ self.to_hash.to_json
89
+ end
90
+
91
+ def map_iap_receipts(receipt_hashes)
92
+ receipt_hashes.map do |tx|
93
+ InAppReceipt.new(tx)
94
+ end
95
+ end
96
+
97
+ class << self
98
+ def verify(data, options = {})
99
+ verify!(data, options) rescue false
100
+ end
101
+
102
+ def verify!(data, options = {})
103
+ client = Client.production
104
+
105
+ begin
106
+ client.verify!(data, options)
107
+ rescue VerificationError => error
108
+ case error.code
109
+ when 21007
110
+ client = Client.development
111
+ retry
112
+ when 21008
113
+ client = Client.production
114
+ retry
115
+ else
116
+ raise error
117
+ end
118
+ end
119
+ end
120
+
121
+ alias :validate :verify
122
+ alias :validate! :verify!
123
+ end
124
+
125
+ class VerificationError < StandardError
126
+ attr_accessor :code
127
+ attr_accessor :receipt_attributes
128
+
129
+ def initialize(code, receipt_attributes)
130
+ @code = Integer(code)
131
+ @receipt_attributes = receipt_attributes
132
+ end
133
+
134
+ def message
135
+ case @code
136
+ when 21000
137
+ "The App Store could not read the JSON object you provided."
138
+ when 21002
139
+ "The data in the receipt-data property was malformed."
140
+ when 21003
141
+ "The receipt could not be authenticated."
142
+ when 21004
143
+ "The shared secret you provided does not match the shared secret on file for your account."
144
+ when 21005
145
+ "The receipt server is not currently available."
146
+ when 21006
147
+ "This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response."
148
+ when 21007
149
+ "This receipt is a sandbox receipt, but it was sent to the production service for verification."
150
+ when 21008
151
+ "This receipt is a production receipt, but it was sent to the sandbox service for verification."
152
+ else
153
+ "Unknown Error: #{@code}"
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,3 @@
1
+ module Venice
2
+ VERSION = "0.2.0"
3
+ end
data/lib/venice.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'venice/version'
2
+ require 'venice/client'
3
+ require 'venice/in_app_receipt'
4
+ require 'venice/receipt'
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fattaholmanan-venice
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Ali Fattaholmanan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
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: commander
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: terminal-table
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.4'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 2.99.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 2.99.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry-byebug
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: ''
112
+ email: fattah@pichak.co
113
+ executables:
114
+ - iap
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - "./Gemfile"
119
+ - "./LICENSE"
120
+ - "./README.md"
121
+ - "./Rakefile"
122
+ - "./fattaholmanan-venice.gemspec"
123
+ - "./lib/venice.rb"
124
+ - "./lib/venice/client.rb"
125
+ - "./lib/venice/in_app_receipt.rb"
126
+ - "./lib/venice/receipt.rb"
127
+ - "./lib/venice/version.rb"
128
+ - bin/iap
129
+ homepage: http://nomad-cli.com
130
+ licenses:
131
+ - MIT
132
+ metadata: {}
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 2.4.6
150
+ signing_key:
151
+ specification_version: 4
152
+ summary: iTunes In-App Purchase Receipt Verification
153
+ test_files: []
154
+ has_rdoc: