apple_receipt 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -0
- data/.travis.yml +2 -0
- data/CHANGELOG.md +7 -0
- data/CODE_OF_CONDUCT.md +3 -6
- data/LICENSE.txt +12 -18
- data/README.md +70 -28
- data/apple_receipt.gemspec +7 -1
- data/certificates/AppleITunesStoreCertificationAuthority.cer +0 -0
- data/certificates/{AppleIncRootCertificate.cer → AppleRootCA.cer} +0 -0
- data/certificates/{AppleWWDRCA.cer → AppleWorldwideDeveloperRelationsCertificationAuthority.cer} +0 -0
- data/lib/apple_receipt/receipt.rb +6 -3
- data/lib/apple_receipt/receipt_parser.rb +24 -9
- data/lib/apple_receipt/validator.rb +27 -10
- data/lib/apple_receipt/version.rb +1 -1
- metadata +49 -7
- data/bin/console +0 -15
- data/bin/setup +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3234acf1d422b851c6e997c905ee974df3be03d446431d894498bf1f0e7e61e
|
4
|
+
data.tar.gz: db024ff11f3ae9a78a98275c9feb9f7fef8d536949a895866ad760a16d3eb185
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7fdcd0d79dee2feedc4c95e8aebd124b58790fc0e12c916fe0a2f948db329eb4a859f299f09507019ee49e8f76809f0e630987d17cfac1267989f0765223cee
|
7
|
+
data.tar.gz: 551a6353876874102e79864b16dca85487054ed6d975a927b2b9ed69bbe22b5228e8aae820c5da249d8627a470e90694dd5ab7e0020bebc7a80f44525ad520f6
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# Apple Receipt changelog
|
2
|
+
|
3
|
+
## v0.2.0
|
4
|
+
|
5
|
+
- Added ISC license [\#5](https://github.com/koenrh/apple_receipt/pull/5)
|
6
|
+
- Added missing dependencies ([\#3](https://github.com/koenrh/apple_receipt/pull/3) and [\#4](https://github.com/koenrh/apple_receipt/pull/4))
|
7
|
+
- Added support for 'version 2' receipts ([\#1](https://github.com/koenrh/apple_receipt/pull/1))
|
data/CODE_OF_CONDUCT.md
CHANGED
@@ -23,7 +23,7 @@ include:
|
|
23
23
|
Examples of unacceptable behavior by participants include:
|
24
24
|
|
25
25
|
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
-
advances
|
26
|
+
advances
|
27
27
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
28
|
* Public or private harassment
|
29
29
|
* Publishing others' private information, such as a physical or electronic
|
@@ -67,8 +67,5 @@ members of the project's leadership.
|
|
67
67
|
|
68
68
|
## Attribution
|
69
69
|
|
70
|
-
This Code of Conduct is adapted from the [Contributor Covenant]
|
71
|
-
|
72
|
-
|
73
|
-
[homepage]: http://contributor-covenant.org
|
74
|
-
[version]: http://contributor-covenant.org/version/1/4/
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/),
|
71
|
+
[version 1.4](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html).
|
data/LICENSE.txt
CHANGED
@@ -1,21 +1,15 @@
|
|
1
|
-
|
1
|
+
ISC License
|
2
2
|
|
3
|
-
Copyright (c) 2018 Koen Rouwhorst
|
3
|
+
Copyright (c) 2018, Koen Rouwhorst
|
4
4
|
|
5
|
-
Permission
|
6
|
-
|
7
|
-
|
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:
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
6
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
7
|
+
and this permission notice appear in all copies.
|
11
8
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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.
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
11
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
13
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
14
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
15
|
+
THIS SOFTWARE.
|
data/README.md
CHANGED
@@ -1,8 +1,15 @@
|
|
1
|
-
#
|
1
|
+
# Apple Receipt
|
2
2
|
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/apple_receipt.svg)](https://badge.fury.io/rb/apple_receipt)
|
3
4
|
[![Build Status](https://travis-ci.org/koenrh/apple_receipt.svg?branch=master)](https://travis-ci.org/koenrh/apple_receipt)
|
5
|
+
[![Dependency Status](https://beta.gemnasium.com/badges/github.com/koenrh/apple_receipt.svg)](https://beta.gemnasium.com/projects/github.com/koenrh/apple_receipt)
|
4
6
|
|
5
|
-
This gem allows you to
|
7
|
+
This gem allows you to read and verify Apple receipts. It was originally built
|
8
|
+
to locally (server-side) verify the validity of receipts that are embedded in
|
9
|
+
[Status Update Notifications](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Subscriptions.html#//apple_ref/doc/uid/TP40008267-CH7-SW13).
|
10
|
+
These receipts have a different format than [documented](https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateLocally.html#//apple_ref/doc/uid/TP40010573-CH1-SW2)
|
11
|
+
App Store receipts you might be familiar with, which are [PKCS #7](https://tools.ietf.org/html/rfc2315)
|
12
|
+
containers with a payload (receipt data) encoded using [ASN.1](https://www.itu.int/itu-t/recommendations/rec.aspx?rec=X.690).
|
6
13
|
|
7
14
|
## Installation
|
8
15
|
|
@@ -25,39 +32,74 @@ Or install it yourself as:
|
|
25
32
|
```ruby
|
26
33
|
require 'apple_receipt'
|
27
34
|
|
28
|
-
#
|
35
|
+
# Check receipt's validity (certificate chain, and signature)
|
29
36
|
receipt_raw = File.read('./receipt.txt')
|
30
37
|
receipt = AppleReceipt::Receipt.new(receipt_raw)
|
31
38
|
receipt.valid?
|
32
39
|
# => true
|
33
40
|
|
34
|
-
#
|
41
|
+
# Read receipt's data (data in example shortened for brevity)
|
35
42
|
receipt.purchase_info
|
36
|
-
# => {
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
# "transaction-id"=>"160000408504141",
|
51
|
-
# "bvrs"=>"7000",
|
52
|
-
# "web-order-line-item-id"=>"160000091314729",
|
53
|
-
# "version-external-identifier"=>"825366855",
|
54
|
-
# "bid"=>"com.foo.bar",
|
55
|
-
# "product-id"=>"com.foo.bar.monthly",
|
56
|
-
# "purchase-date"=>"2017-12-23 17:03:44 Etc/GMT",
|
57
|
-
# "purchase-date-pst"=>"2017-12-23 09:03:44 America/Los_Angeles",
|
58
|
-
# "original-purchase-date"=>"2017-12-23 17:03:53 Etc/GMT"}
|
43
|
+
# => {
|
44
|
+
# "quantity"=>"1",
|
45
|
+
# "expires-date-formatted"=>"2018-01-23 17:03:44 Etc/GMT",
|
46
|
+
# "is-in-intro-offer-period"=>"false",
|
47
|
+
# "is-trial-period"=>"false",
|
48
|
+
# "item-id"=>"1190360447",
|
49
|
+
# "app-item-id"=>"947936149",
|
50
|
+
# "transaction-id"=>"160000408504141",
|
51
|
+
# "web-order-line-item-id"=>"160000011000001",
|
52
|
+
# "bid"=>"com.foo.bar",
|
53
|
+
# "product-id"=>"com.foo.bar.monthly",
|
54
|
+
# "purchase-date"=>"2017-12-23 17:03:44 Etc/GMT",
|
55
|
+
# "original-purchase-date"=>"2017-12-23 17:03:53 Etc/GMT"
|
56
|
+
# }
|
59
57
|
```
|
60
58
|
|
59
|
+
## Apple receipts
|
60
|
+
|
61
|
+
A receipt is encoded as base64, and is formatted as a [NeXTSTEP](https://en.wikipedia.org/wiki/Property_list#NeXTSTEP)
|
62
|
+
dictionary:
|
63
|
+
|
64
|
+
```
|
65
|
+
{
|
66
|
+
"signature" = "[base64-encoded signature]";
|
67
|
+
"purchase-info" = "[base64-encoded purchase data]";
|
68
|
+
"pod" = "[integer]";
|
69
|
+
"signing-status" = "0";
|
70
|
+
}
|
71
|
+
```
|
72
|
+
|
73
|
+
### Signature
|
74
|
+
|
75
|
+
The `signature` entry contains base64-encoded binary data, which has the following
|
76
|
+
layout:
|
77
|
+
|
78
|
+
- **1 byte** - Receipt version (e.g. version 3).
|
79
|
+
- **128 bytes** (version 2) or **256 bytes** (version 3) - Signature.
|
80
|
+
- **4 bytes** - Length (in number of bytes) of the certificate.
|
81
|
+
- **N bytes** - DER-encoded certificate.
|
82
|
+
|
83
|
+
The version 2 and 3 receipt certificates are signed, respectively, by:
|
84
|
+
|
85
|
+
- **Apple iTunes Store Certification Authority** (version 2)
|
86
|
+
- Serial: 26 (`0x1a`)
|
87
|
+
- Subject: `C=US, O=Apple Inc., OU=Apple Certification Authority, CN=Apple iTunes Store Certification Authority`
|
88
|
+
- **Apple Worldwide Developer Relations Certification Authority** (version 3)
|
89
|
+
- Serial: 134752589830791184 (`0x1debcc4396da010`)
|
90
|
+
- Subject: `C=US, O=Apple Inc., OU=Apple Worldwide Developer Relations, CN=Apple Worldwide Developer Relations Certification Authority`
|
91
|
+
|
92
|
+
Both certificates chain up to:
|
93
|
+
|
94
|
+
- **Apple Root CA**
|
95
|
+
- Serial: 2 (`0x2`)
|
96
|
+
- Subject: `C=US, O=Apple Inc., OU=Apple Certification Authority, CN=Apple Root CA`
|
97
|
+
|
98
|
+
### Purchase info
|
99
|
+
|
100
|
+
The `purchase-info` entry contains a base64-encoded NeXTSTEP dictionary that contains
|
101
|
+
the actual receipt data (purchase info).
|
102
|
+
|
61
103
|
## Contributing
|
62
104
|
|
63
105
|
Bug reports and pull requests are welcome on [GitHub](https://github.com/koenrh/apple_receipt).
|
@@ -67,4 +109,4 @@ code of conduct.
|
|
67
109
|
|
68
110
|
## License
|
69
111
|
|
70
|
-
The gem is available as open source under the terms of the [
|
112
|
+
The gem is available as open source under the terms of the [ISC License](https://opensource.org/licenses/ISC).
|
data/apple_receipt.gemspec
CHANGED
@@ -5,6 +5,7 @@ lib = File.expand_path('../lib', __FILE__)
|
|
5
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
6
|
require 'apple_receipt/version'
|
7
7
|
|
8
|
+
# rubocop:disable Metrics/BlockLength
|
8
9
|
Gem::Specification.new do |spec|
|
9
10
|
spec.name = 'apple_receipt'
|
10
11
|
spec.version = AppleReceipt::VERSION
|
@@ -30,8 +31,13 @@ Gem::Specification.new do |spec|
|
|
30
31
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
31
32
|
spec.require_paths = ['lib']
|
32
33
|
|
34
|
+
spec.add_dependency 'json', '~> 2.0'
|
35
|
+
spec.add_dependency 'openssl', '~> 2.0'
|
36
|
+
|
33
37
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
34
38
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
35
|
-
spec.add_development_dependency '
|
39
|
+
spec.add_development_dependency 'mocha', '~> 1.3'
|
40
|
+
spec.add_development_dependency 'rake', '~> 12.0'
|
36
41
|
spec.add_development_dependency 'rubocop', '~> 0.50'
|
37
42
|
end
|
43
|
+
# rubocop:enable Metrics/BlockLength
|
Binary file
|
File without changes
|
data/certificates/{AppleWWDRCA.cer → AppleWorldwideDeveloperRelationsCertificationAuthority.cer}
RENAMED
File without changes
|
@@ -11,17 +11,20 @@ module AppleReceipt
|
|
11
11
|
class Receipt
|
12
12
|
def initialize(raw_receipt)
|
13
13
|
receipt_decoded = Base64.decode64(raw_receipt)
|
14
|
-
@version,
|
14
|
+
@version,
|
15
|
+
@signature,
|
16
|
+
@certificate,
|
17
|
+
@data = ReceiptParser.parse(receipt_decoded)
|
15
18
|
end
|
16
19
|
|
17
20
|
def purchase_info
|
18
|
-
NextStepParser.parse(data)
|
21
|
+
@purchase_info ||= NextStepParser.parse(data)
|
19
22
|
end
|
20
23
|
|
21
24
|
def valid?
|
22
25
|
Validator.new(self).valid?
|
23
26
|
end
|
24
27
|
|
25
|
-
attr_reader :version, :signature, :
|
28
|
+
attr_reader :version, :signature, :certificate, :data
|
26
29
|
end
|
27
30
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'base64'
|
4
4
|
require 'openssl'
|
5
5
|
require 'json'
|
6
|
+
require 'set'
|
6
7
|
|
7
8
|
require 'apple_receipt/next_step_parser'
|
8
9
|
|
@@ -11,24 +12,38 @@ module AppleReceipt
|
|
11
12
|
module ReceiptParser
|
12
13
|
module_function
|
13
14
|
|
14
|
-
|
15
|
+
SIGNATURE_LENGTH_MAPPING = {
|
16
|
+
2 => 128,
|
17
|
+
3 => 256
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
def parse(input)
|
15
21
|
receipt_hash = NextStepParser.parse(input)
|
22
|
+
|
23
|
+
unless Set['signature', 'purchase-info'].subset?(receipt_hash.keys.to_set)
|
24
|
+
raise ArgumentError, 'Missing required fields'
|
25
|
+
end
|
26
|
+
|
16
27
|
signature_decoded = Base64.decode64(receipt_hash['signature'])
|
17
|
-
|
28
|
+
data_decoded = Base64.decode64(receipt_hash['purchase-info'])
|
18
29
|
|
19
|
-
|
20
|
-
[
|
30
|
+
version, signature, receipt_cert = read_signature(signature_decoded)
|
31
|
+
[version, signature, receipt_cert, data_decoded]
|
21
32
|
end
|
22
33
|
|
23
|
-
def
|
24
|
-
sig
|
25
|
-
|
34
|
+
def read_signature(signature_decoded)
|
35
|
+
sig = StringIO.new(signature_decoded)
|
26
36
|
version = sig.read(1).unpack('C').first # 8-bit unsigned (unsigned char)
|
27
|
-
|
37
|
+
|
38
|
+
unless SIGNATURE_LENGTH_MAPPING.keys.include?(version)
|
39
|
+
raise ArgumentError, "Unsupported receipt version: #{version}"
|
40
|
+
end
|
41
|
+
|
42
|
+
signature = sig.read(SIGNATURE_LENGTH_MAPPING[version])
|
28
43
|
cert_size = sig.read(4).unpack('L>')[0] # 32-bit unsigned, big-endian
|
29
44
|
receipt_cert = OpenSSL::X509::Certificate.new(sig.read(cert_size))
|
30
45
|
|
31
|
-
[version, signature, receipt_cert
|
46
|
+
[version, signature, receipt_cert]
|
32
47
|
end
|
33
48
|
end
|
34
49
|
end
|
@@ -5,27 +5,44 @@ require 'openssl'
|
|
5
5
|
module AppleReceipt
|
6
6
|
# Validator allows one to check the validity of a receipt.
|
7
7
|
class Validator
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
INTERMEDIATE_CERT_MAPPING = {
|
9
|
+
3 => 'AppleWorldwideDeveloperRelationsCertificationAuthority',
|
10
|
+
2 => 'AppleITunesStoreCertificationAuthority'
|
11
|
+
}.freeze
|
11
12
|
|
12
|
-
|
13
|
-
|
13
|
+
def initialize(receipt, certificates: [])
|
14
|
+
populate_certificate_store(receipt.version, certificates)
|
15
|
+
@receipt = receipt
|
16
|
+
end
|
17
|
+
|
18
|
+
def populate_certificate_store(version, provided_certificates)
|
19
|
+
if provided_certificates.any?
|
20
|
+
add_certificates(provided_certificates)
|
21
|
+
else
|
22
|
+
add_named_certificate('AppleRootCA')
|
23
|
+
add_named_certificate(INTERMEDIATE_CERT_MAPPING[version])
|
24
|
+
end
|
25
|
+
end
|
14
26
|
|
15
|
-
|
16
|
-
|
27
|
+
def add_named_certificate(name)
|
28
|
+
cert_file = File.read("./certificates/#{name}.cer")
|
29
|
+
store.add_cert(OpenSSL::X509::Certificate.new(cert_file))
|
30
|
+
end
|
17
31
|
|
18
|
-
|
32
|
+
def add_certificates(certificates)
|
33
|
+
certificates.each do |cert|
|
34
|
+
store.add_cert(cert)
|
35
|
+
end
|
19
36
|
end
|
20
37
|
|
21
38
|
def valid?
|
22
|
-
store.verify(receipt.
|
39
|
+
store.verify(receipt.certificate) &&
|
23
40
|
public_key.verify(OpenSSL::Digest::SHA1.new,
|
24
41
|
receipt.signature, signed_data)
|
25
42
|
end
|
26
43
|
|
27
44
|
def public_key
|
28
|
-
receipt.
|
45
|
+
receipt.certificate.public_key
|
29
46
|
end
|
30
47
|
|
31
48
|
def signed_data
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apple_receipt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Koen Rouwhorst
|
@@ -10,6 +10,34 @@ bindir: exe
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 2018-01-27 00:00:00.000000000 Z
|
12
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: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: openssl
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
13
41
|
- !ruby/object:Gem::Dependency
|
14
42
|
name: bundler
|
15
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,20 +66,34 @@ dependencies:
|
|
38
66
|
- - "~>"
|
39
67
|
- !ruby/object:Gem::Version
|
40
68
|
version: '5.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: mocha
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.3'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.3'
|
41
83
|
- !ruby/object:Gem::Dependency
|
42
84
|
name: rake
|
43
85
|
requirement: !ruby/object:Gem::Requirement
|
44
86
|
requirements:
|
45
87
|
- - "~>"
|
46
88
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
89
|
+
version: '12.0'
|
48
90
|
type: :development
|
49
91
|
prerelease: false
|
50
92
|
version_requirements: !ruby/object:Gem::Requirement
|
51
93
|
requirements:
|
52
94
|
- - "~>"
|
53
95
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
96
|
+
version: '12.0'
|
55
97
|
- !ruby/object:Gem::Dependency
|
56
98
|
name: rubocop
|
57
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -76,16 +118,16 @@ files:
|
|
76
118
|
- ".gitignore"
|
77
119
|
- ".rubocop.yml"
|
78
120
|
- ".travis.yml"
|
121
|
+
- CHANGELOG.md
|
79
122
|
- CODE_OF_CONDUCT.md
|
80
123
|
- Gemfile
|
81
124
|
- LICENSE.txt
|
82
125
|
- README.md
|
83
126
|
- Rakefile
|
84
127
|
- apple_receipt.gemspec
|
85
|
-
-
|
86
|
-
-
|
87
|
-
- certificates/
|
88
|
-
- certificates/AppleWWDRCA.cer
|
128
|
+
- certificates/AppleITunesStoreCertificationAuthority.cer
|
129
|
+
- certificates/AppleRootCA.cer
|
130
|
+
- certificates/AppleWorldwideDeveloperRelationsCertificationAuthority.cer
|
89
131
|
- lib/apple_receipt.rb
|
90
132
|
- lib/apple_receipt/next_step_parser.rb
|
91
133
|
- lib/apple_receipt/receipt.rb
|
data/bin/console
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require 'bundler/setup'
|
5
|
-
require 'apple_receipt'
|
6
|
-
|
7
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
-
# with your gem easier. You can also use a different console, if you like.
|
9
|
-
|
10
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
-
# require "pry"
|
12
|
-
# Pry.start
|
13
|
-
|
14
|
-
require 'irb'
|
15
|
-
IRB.start(__FILE__)
|