imobile 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/LICENSE +21 -0
- data/Manifest +10 -0
- data/README +6 -0
- data/Rakefile +22 -0
- data/imobile.gemspec +40 -0
- data/lib/imobile/validate_receipt.rb +104 -0
- data/lib/imobile.rb +7 -0
- data/test/validate_receipt_test.rb +50 -0
- data/testdata/forged_sandbox_receipt +6 -0
- data/testdata/valid_sandbox_receipt +6 -0
- metadata +103 -0
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
data/README
ADDED
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,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
|