imobile 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG ADDED
@@ -0,0 +1 @@
1
+ v0.0.1. Initial release. In-App Purchase receipt validation.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2009 Zergling.Net
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/Manifest ADDED
@@ -0,0 +1,10 @@
1
+ CHANGELOG
2
+ lib/imobile/validate_receipt.rb
3
+ lib/imobile.rb
4
+ LICENSE
5
+ Manifest
6
+ Rakefile
7
+ README
8
+ test/validate_receipt_test.rb
9
+ testdata/forged_sandbox_receipt
10
+ testdata/valid_sandbox_receipt
data/README ADDED
@@ -0,0 +1,6 @@
1
+ This gem/Rails plugin contains common code for powering iPhone applications. It
2
+ is particularly suitable as a server-side partner to the ZergSupport toolkit,
3
+ also available on Github under the MIT license at
4
+ http://github.com/costan/zergsupport
5
+
6
+
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'echoe'
3
+
4
+ Echoe.new('imobile') do |p|
5
+ p.project = 'zerglings' # rubyforge project
6
+
7
+ p.author = 'Victor Costan'
8
+ p.email = 'victor@zergling.net'
9
+ p.summary = 'Library for servers backing iPhone applications.'
10
+ p.url = 'http://github.com/costan/imobile'
11
+ p.dependencies = ['json >=1.1.7']
12
+ p.development_dependencies = ["echoe >=3.1.1", "flexmock >=0.8.6"]
13
+
14
+ p.need_tar_gz = true
15
+ p.need_zip = true
16
+ p.rdoc_pattern = /^(lib|bin|tasks|ext)|^BUILD|^README|^CHANGELOG|^TODO|^LICENSE|^COPYING$/
17
+ end
18
+
19
+ if $0 == __FILE__
20
+ Rake.application = Rake::Application.new
21
+ Rake.application.run
22
+ end
data/imobile.gemspec ADDED
@@ -0,0 +1,40 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{imobile}
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Victor Costan"]
9
+ s.date = %q{2009-07-23}
10
+ s.description = %q{Library for servers backing iPhone applications.}
11
+ s.email = %q{victor@zergling.net}
12
+ s.extra_rdoc_files = ["CHANGELOG", "lib/imobile/validate_receipt.rb", "lib/imobile.rb", "LICENSE", "README"]
13
+ s.files = ["CHANGELOG", "lib/imobile/validate_receipt.rb", "lib/imobile.rb", "LICENSE", "Manifest", "Rakefile", "README", "test/validate_receipt_test.rb", "testdata/forged_sandbox_receipt", "testdata/valid_sandbox_receipt", "imobile.gemspec"]
14
+ s.homepage = %q{http://github.com/costan/imobile}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Imobile", "--main", "README"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{zerglings}
18
+ s.rubygems_version = %q{1.3.5}
19
+ s.summary = %q{Library for servers backing iPhone applications.}
20
+ s.test_files = ["test/validate_receipt_test.rb"]
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 3
25
+
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
+ s.add_runtime_dependency(%q<json>, [">= 1.1.7"])
28
+ s.add_development_dependency(%q<echoe>, [">= 3.1.1"])
29
+ s.add_development_dependency(%q<flexmock>, [">= 0.8.6"])
30
+ else
31
+ s.add_dependency(%q<json>, [">= 1.1.7"])
32
+ s.add_dependency(%q<echoe>, [">= 3.1.1"])
33
+ s.add_dependency(%q<flexmock>, [">= 0.8.6"])
34
+ end
35
+ else
36
+ s.add_dependency(%q<json>, [">= 1.1.7"])
37
+ s.add_dependency(%q<echoe>, [">= 3.1.1"])
38
+ s.add_dependency(%q<flexmock>, [">= 0.8.6"])
39
+ end
40
+ end
@@ -0,0 +1,104 @@
1
+ # Online validation for receipt blobs generated by the In-App Purchase process.
2
+ #
3
+ # Author:: Victor Costan
4
+ # Copyright:: Copyright (C) 2009 Zergling.Net
5
+ # License:: MIT
6
+
7
+ require 'base64'
8
+ require 'date'
9
+ require 'net/http'
10
+ require 'net/https'
11
+ require 'openssl'
12
+ require 'time'
13
+
14
+ require 'rubygems'
15
+ require 'json'
16
+
17
+
18
+ # :nodoc: namespace
19
+ module Imobile
20
+
21
+ # Decodes and validates an In-App Purchase receipt from the App Store.
22
+ #
23
+ # Args:
24
+ # receipt_blob:: raw receipt in SKPaymentTransaction.transactionReceipt
25
+ # server_type:: production or sandbox (the API accepts symbols and strings)
26
+ #
27
+ # The decoded receipt is returned as a Ruby-friendly hash. Keys are converted to
28
+ # snake_case symbols (e.g. 'purchase-date' becomes :purchase_date). Dates and
29
+ # relevant numbers are parsed out of the JSON strings.
30
+ #
31
+ # Returns +false+ if validation fails (the receipt was tampered with). Raises a
32
+ # RuntimeException if Apple's Web service returns a HTTP error code.
33
+ def self.validate_receipt(receipt_blob, server_type = :sandbox)
34
+ AppStoreReceiptValidation.validate_receipt receipt_blob
35
+ end
36
+
37
+
38
+ # Implementation details for validate_receipt.
39
+ module AppStoreReceiptValidation
40
+ # An URI object pointing to the App Store receipt validating server.
41
+ #
42
+ # The server type is production or sandbox (strings and symbols work).
43
+ def self.store_uri(server_type)
44
+ uri_string = {
45
+ :production => "https://buy.itunes.apple.com/verifyReceipt",
46
+ :sandbox => "https://sandbox.itunes.apple.com/verifyReceipt"
47
+ }[server_type.to_sym]
48
+
49
+ uri_string and URI.parse(uri_string)
50
+ end
51
+
52
+ # A Net:HTTP request for validating a receipt.
53
+ def self.request(receipt_blob, store_uri)
54
+ request = Net::HTTP::Post.new store_uri.path
55
+ request.set_content_type 'application/json'
56
+ request.body = {'receipt-data' => Base64.encode64(receipt_blob) }.to_json
57
+ request
58
+ end
59
+
60
+ # Issues a HTTP request to Apple's receipt validating server.
61
+ def self.issue_request(http_request, store_uri)
62
+ http = Net::HTTP.new store_uri.host, store_uri.port
63
+ http.use_ssl = (store_uri.scheme == 'https')
64
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
65
+ http.request http_request
66
+ end
67
+
68
+ # Turns JSON receipt information into a nice Ruby-like receipt.
69
+ #
70
+ # String keys are mapped to Ruby symbols (e.g. 'purchase-date' becomes
71
+ # :purchase_date) and date strings are parsed to Ruby dates.
72
+ def self.nice_receipt(json_receipt)
73
+ nice = Hash[*json_receipt.map { |key, value|
74
+ [key.gsub('-', '_').to_sym, value]
75
+ }.flatten]
76
+
77
+ [:purchase_date, :original_purchase_date].each do |key|
78
+ nice[key] = DateTime.parse(nice[key]) if nice[key]
79
+ end
80
+ nice[:quantity] = nice[:quantity].to_i if nice[:quantity]
81
+
82
+ nice
83
+ end
84
+
85
+ # Processes a HTTP response into a receipt.
86
+ def self.process_response(http_response)
87
+ unless http_response.kind_of? Net::HTTPSuccess
88
+ raise "Internal error in Apple's Web service -- #{http_response.inspect}"
89
+ end
90
+
91
+ response = JSON.parse http_response.body
92
+ return false unless response['status'] == 0
93
+ nice_receipt response['receipt']
94
+ end
95
+
96
+ # Real implementation of Imobile.validate_receipt
97
+ def self.validate_receipt(receipt_blob, server_type = :production)
98
+ uri = store_uri server_type
99
+
100
+ process_response issue_request(request(receipt_blob, uri), uri)
101
+ end
102
+ end
103
+
104
+ end # namespace Imobile
data/lib/imobile.rb ADDED
@@ -0,0 +1,7 @@
1
+ # Master include file for the Imobile gem / plug-in.
2
+ #
3
+ # Author:: Victor Costan
4
+ # Copyright:: Copyright (C) 2009 Zergling.Net
5
+ # License:: MIT
6
+
7
+ require 'imobile/validate_receipt.rb'
@@ -0,0 +1,50 @@
1
+ # Author:: Victor Costan
2
+ # Copyright:: Copyright (C) 2009 Zergling.Net
3
+ # License:: MIT
4
+
5
+ require 'imobile'
6
+
7
+ require 'time'
8
+ require 'test/unit'
9
+
10
+
11
+ class ValidateReceiptTest < Test::Unit::TestCase
12
+ def setup
13
+ testdata_path = File.join(File.dirname(__FILE__), '..', 'testdata')
14
+
15
+ @forged_sandbox_blob = File.read File.join(testdata_path,
16
+ 'forged_sandbox_receipt')
17
+ @valid_sandbox_blob = File.read File.join(testdata_path,
18
+ 'valid_sandbox_receipt')
19
+ end
20
+
21
+ def test_valid_sandbox_receipt
22
+ golden_date = Time.parse('2009-07-22 18:52:46 EEST')
23
+
24
+ receipt = Imobile.validate_receipt @valid_sandbox_blob, :sandbox
25
+ assert receipt, "Genuine receipt failed validation"
26
+
27
+ assert_equal 1, receipt[:quantity], 'Wrong quantity'
28
+ assert_equal 'us.costan.ZergSupportTests', receipt[:bid], 'Wrong bundle ID'
29
+ assert_equal '1.9.8.3', receipt[:bvrs], 'Wrong bundle version'
30
+ assert_equal 'net.zergling.ZergSupport.sub_cheap', receipt[:product_id],
31
+ 'Wrong product ID'
32
+ assert_equal '324740515', receipt[:item_id], 'Wrong item (iTunes app) ID'
33
+ assert_equal '1000000000016600', receipt[:transaction_id],
34
+ 'Wrong transaction ID'
35
+ assert_equal '1000000000016600', receipt[:original_transaction_id],
36
+ 'Wrong original transaction ID'
37
+ assert_equal golden_date.to_f,
38
+ Time.parse(receipt[:purchase_date].to_s).to_f,
39
+ 'Wrong purchase date'
40
+ assert_equal golden_date.to_f,
41
+ Time.parse(receipt[:original_purchase_date].to_s).to_f,
42
+ 'Wrong original purchase date'
43
+ end
44
+
45
+ def test_forged_sandbox_receipt
46
+ assert_equal false,
47
+ Imobile.validate_receipt(@forged_sandbox_blob, :sandbox),
48
+ "Forged receipt passed validation"
49
+ end
50
+ end
@@ -0,0 +1,6 @@
1
+ {
2
+ "signature" = "AUXu7Ofn0I4Zl7kghQOLSDB17PzQT0lscGJfFiFsJFT0q9BFGG0ynHJAOARZMXdUFnb87YxrhqD1pm7KPxqgs18mndMRkw/fcRDgMIRmp4nsQlISF8mRqrkYqehHPTXwd75YxpBRkKil8qYciQRMuQEAhL8C5M+ycXzIpTgF2l1pMIIDUzCCAjugAwIBAgIIZRSRTdlYBLUwDQYJKoZIhvcNAQEFBQAwfzELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkFwcGxlIEluYy4xJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTMwMQYDVQQDDCpBcHBsZSBpVHVuZXMgU3RvcmUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDkwNjE1MjIwNTU2WhcNMTQwNjE0MjIwNTU2WjBkMSMwIQYDVQQDDBpQdXJjaGFzZVJlY2VpcHRDZXJ0aWZpY2F0ZTEbMBkGA1UECwwSQXBwbGUgaVR1bmVzIFN0b3JlMRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAytGMXZy3gitJ2JMKFojSDynC/9yYezyn9HBX+u3/3VcpWE2XhcgGKYqNBA1+AewOzrKO774OsokTu4qymEx10ph8UTmsZewB0ESMHBEjF7FN6/HccsQUYC3WagrHnT12HG2Ih0OAm/ZhpWzj0HS4m813LpIyo00sewMvMNL2hkcCAwEAAaNyMHAwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBQ2HejinYLSARi1MmsO10MLkVhDOjAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFKmDg/IZSMU+ElcIFMzNo36ZXyT1MBAGCiqGSIb3Y2QGBQEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQARpJs+O2Y3gL8gHdASkrfZHFpwINd1VcB5VF5LkVpnFz63zylA/3cGIDG91b/d5NIwZjkVt4Bgvd62o/mCbzCsWiNfSKTJVFK1D78BDQoSO2oHTuQuz1BR7xzNHxQZ90zUS6ZX9SC8N3g3A1jEtAyDhZNB+CRBBXLwZdnBUeBsT9QLpjvTnekZcGTnU08zfCjGF3eBJEu9eP6WgexK1xMSp72kEOmYbn6yTi3D4YrcYx4Q3n/57VBP2en8qXWeP5oHDsLTGzLRsWdoB3VxJLrF2ivL8JS8zqC0qyac452pN6xunRuzyyfpaqzQL12BzFEe44xna2byektSbtquA5LNAAAAAA==";
3
+ "purchase-info" = "ewoJIml0ZW0taWQiID0gIjMyNDc0MDUxNSI7Cgkib3JpZ2luYWwtdHJhbnNhY3Rpb24taWQiID0gIjEwMDAwMDAwMDAwMTY2MDAiOwoJInB1cmNoYXNlLWRhdGUiID0gIjIwMDktMDctMjIgMjI6NTI6NDYgRXRjL0dNVCI7CgkicHJvZHVjdC1pZCIgPSAibmV0LnplcmdsaW5nLlplcmdTdXBwb3J0LnN1Yl9jaGVhcCI7CgkidHJhbnNhY3Rpb24taWQiID0gIjEwMDAwMDAwMDAwMTY2MDAiOwoJInF1YW50aXR5IiA9ICIxIjsKCSJvcmlnaW5hbC1wdXJjaGFzZS1kYXRlIiA9ICIyMDA5LTA3LTIyIDIyOjUyOjQ2IEV0Yy9HTVQiOwoJImJpZCIgPSAidXMuY29zdGFuLlplcmdTdXBwb3J0VGVzdHMiOwoJImJ2cnMiID0gIjEuOS44LjMiOwpA";
4
+ "pod" = "100";
5
+ "signing-status" = "0";
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "signature" = "AUXu7Ofn0I4Zl7kghQOLSDB17PzQT0lscGJfFiFsJFT0q9BFGG0ynHJAOARZMXdUFnb87YxrhqD1pm7KPxqgs18mndMRkw/fcRDgMIRmp4nsQlISF8mRqrkYqehHPTXwd75YxpBRkKil8qYciQRMuQEAhL8C5M+ycXzIpTgF2l1pMIIDUzCCAjugAwIBAgIIZRSRTdlYBLUwDQYJKoZIhvcNAQEFBQAwfzELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkFwcGxlIEluYy4xJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTMwMQYDVQQDDCpBcHBsZSBpVHVuZXMgU3RvcmUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDkwNjE1MjIwNTU2WhcNMTQwNjE0MjIwNTU2WjBkMSMwIQYDVQQDDBpQdXJjaGFzZVJlY2VpcHRDZXJ0aWZpY2F0ZTEbMBkGA1UECwwSQXBwbGUgaVR1bmVzIFN0b3JlMRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAytGMXZy3gitJ2JMKFojSDynC/9yYezyn9HBX+u3/3VcpWE2XhcgGKYqNBA1+AewOzrKO774OsokTu4qymEx10ph8UTmsZewB0ESMHBEjF7FN6/HccsQUYC3WagrHnT12HG2Ih0OAm/ZhpWzj0HS4m813LpIyo00sewMvMNL2hkcCAwEAAaNyMHAwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBQ2HejinYLSARi1MmsO10MLkVhDOjAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFKmDg/IZSMU+ElcIFMzNo36ZXyT1MBAGCiqGSIb3Y2QGBQEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQARpJs+O2Y3gL8gHdASkrfZHFpwINd1VcB5VF5LkVpnFz63zylA/3cGIDG91b/d5NIwZjkVt4Bgvd62o/mCbzCsWiNfSKTJVFK1D78BDQoSO2oHTuQuz1BR7xzNHxQZ90zUS6ZX9SC8N3g3A1jEtAyDhZNB+CRBBXLwZdnBUeBsT9QLpjvTnekZcGTnU08zfCjGF3eBJEu9eP6WgexK1xMSp72kEOmYbn6yTi3D4YrcYx4Q3n/57VBP2en8qXWeP5oHDsLTGzLRsWdoB3VxJLrF2ivL8JS8zqC0qyac452pN6xunRuzyyfpaqzQL12BzFEe44xna2byektSbtquA5LNAAAAAA==";
3
+ "purchase-info" = "ewoJIml0ZW0taWQiID0gIjMyNDc0MDUxNSI7Cgkib3JpZ2luYWwtdHJhbnNhY3Rpb24taWQiID0gIjEwMDAwMDAwMDAwMTY2MDAiOwoJInB1cmNoYXNlLWRhdGUiID0gIjIwMDktMDctMjIgMjI6NTI6NDYgRXRjL0dNVCI7CgkicHJvZHVjdC1pZCIgPSAibmV0LnplcmdsaW5nLlplcmdTdXBwb3J0LnN1Yl9jaGVhcCI7CgkidHJhbnNhY3Rpb24taWQiID0gIjEwMDAwMDAwMDAwMTY2MDAiOwoJInF1YW50aXR5IiA9ICIxIjsKCSJvcmlnaW5hbC1wdXJjaGFzZS1kYXRlIiA9ICIyMDA5LTA3LTIyIDIyOjUyOjQ2IEV0Yy9HTVQiOwoJImJpZCIgPSAidXMuY29zdGFuLlplcmdTdXBwb3J0VGVzdHMiOwoJImJ2cnMiID0gIjEuOS44LjMiOwp9";
4
+ "pod" = "100";
5
+ "signing-status" = "0";
6
+ }
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: imobile
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Victor Costan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-23 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: json
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.7
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: echoe
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 3.1.1
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: flexmock
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.8.6
44
+ version:
45
+ description: Library for servers backing iPhone applications.
46
+ email: victor@zergling.net
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - CHANGELOG
53
+ - lib/imobile/validate_receipt.rb
54
+ - lib/imobile.rb
55
+ - LICENSE
56
+ - README
57
+ files:
58
+ - CHANGELOG
59
+ - lib/imobile/validate_receipt.rb
60
+ - lib/imobile.rb
61
+ - LICENSE
62
+ - Manifest
63
+ - Rakefile
64
+ - README
65
+ - test/validate_receipt_test.rb
66
+ - testdata/forged_sandbox_receipt
67
+ - testdata/valid_sandbox_receipt
68
+ - imobile.gemspec
69
+ has_rdoc: true
70
+ homepage: http://github.com/costan/imobile
71
+ licenses: []
72
+
73
+ post_install_message:
74
+ rdoc_options:
75
+ - --line-numbers
76
+ - --inline-source
77
+ - --title
78
+ - Imobile
79
+ - --main
80
+ - README
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: "0"
88
+ version:
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: "1.2"
94
+ version:
95
+ requirements: []
96
+
97
+ rubyforge_project: zerglings
98
+ rubygems_version: 1.3.5
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: Library for servers backing iPhone applications.
102
+ test_files:
103
+ - test/validate_receipt_test.rb