itunes_receipt_decoder 0.3.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: be8ac7da532b84da681984f7e5e51e8677133d77
4
- data.tar.gz: fc0888f8a80f019e20059535fe6e926ed5c56e40
3
+ metadata.gz: a6838ab6252d5ec860f98df20e04bca32f93b801
4
+ data.tar.gz: bfe44e8887c1867ea74b2de25dd8e979383ff97a
5
5
  SHA512:
6
- metadata.gz: 056453f28cb7f4b62464736c07cbdc90bfe53aa1802d371075fe418146646d11312047cbec620edea1620c4f0b1b4a80319992db6bbf63f93b28314ce3ada481
7
- data.tar.gz: b9d31eb78fef4c3753aa19f610cf092474757bee9b01339b303e8a853a286c30405244fcea628a00bb375a9460b97c4cd9b48e3fbab4bb8b1577a8989c39ae89
6
+ metadata.gz: 07bbd06b2c295609c2123fd45a3261bfc8beafa8cdb1453d973c0a651ea3c8fe46ccf28de426b65bcaf9a5f90a5836121d5d57ea345d00f58168f74cef76773a
7
+ data.tar.gz: fb7050fc14c45a0a1affd783ab6fa2d365bae45c849188039203f5436ceaf1e742f9661225bf87a1dcac57f6a4d0464c466823bb06c4b66796e9d1ec61e5dc23
@@ -1,6 +1,7 @@
1
1
  require 'openssl'
2
2
  require 'cfpropertylist'
3
3
  require 'itunes_receipt_decoder/decode/base'
4
+ require 'itunes_receipt_decoder/public_key'
4
5
 
5
6
  ##
6
7
  # ItunesReceiptDecoder
@@ -11,44 +12,77 @@ module ItunesReceiptDecoder
11
12
  ##
12
13
  # ItunesReceiptDecoder::Decode::TransactionReceipt
13
14
  class TransactionReceipt < Base
14
- PUBLIC_KEY = OpenSSL::PKey::RSA.new <<-PUBLIC_KEY
15
- -----BEGIN PUBLIC KEY-----
16
- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApLyvMpRDPgu8N4fNY4ny
17
- zNm+IE1atP6HZ9Ka3hpUnaLz34fkTMuTEXigMI80QcHTvmZtR2yYuOx61cndpeTq
18
- xnD0NdCR97PYChGZqzpiOr179FZP258kk1FQfCDVZk1m8xikE5YiFv0xp/Q5Zpv7
19
- YmlcS5+UqEvo7FtkWhh5ihZ1Y0KkSdmMM96te9Y5BPTinQppjOtLEihLNEgHmw5Z
20
- +R9isAOfNrhOo9N1WdTzOgXKxTM7+MAGCQiT2+dNvxHzUiylFjUV80ECzQLR/PX4
21
- xYS9Y2qG1raZ9oauX/0D1CiKWl2vvGV00fcaw5II9BytaegCTA6VFQe8vmpvwbOt
22
- oQIDAQAB
23
- -----END PUBLIC KEY-----
24
- PUBLIC_KEY
15
+ ##
16
+ # ItunesReceiptDecoder::Decode::TransactionReceipt::SignatureValidation
17
+ class SignatureValidation
18
+ attr_reader :blob, :purchase_info
19
+ attr_accessor :version, :signature, :raw_cert, :cert_length
20
+
21
+ def initialize(blob, purchase_info)
22
+ @blob = blob
23
+ @purchase_info = purchase_info
24
+ end
25
+
26
+ def valid?
27
+ unpack &&
28
+ raw_cert.size == cert_length &&
29
+ cert &&
30
+ cert.verify(public_key) &&
31
+ verify
32
+ end
33
+
34
+ private
35
+
36
+ def verify
37
+ data = [version, purchase_info].pack('ca*')
38
+ cert.public_key.verify(OpenSSL::Digest::SHA1.new, signature, data)
39
+ end
40
+
41
+ def cert
42
+ @cert ||= OpenSSL::X509::Certificate.new(raw_cert)
43
+ rescue OpenSSL::X509::CertificateError => _e
44
+ false
45
+ end
46
+
47
+ def unpack
48
+ self.version, following = blob.unpack('c a*')
49
+ return false unless [2, 3].include?(version)
50
+ arrangement =
51
+ case version
52
+ when 2 then 'a128 N a*'
53
+ when 3 then 'a256 N a*'
54
+ end
55
+ self.signature, self.cert_length, self.raw_cert =
56
+ following.unpack(arrangement)
57
+ end
58
+
59
+ def public_key
60
+ @public_key ||=
61
+ case version
62
+ when 2 then PublicKey::V2
63
+ when 3 then PublicKey::V3
64
+ end
65
+ end
66
+ end
25
67
 
26
68
  def style
27
69
  :transaction
28
70
  end
29
71
 
30
72
  def signature_valid?
31
- version, sig, cert_length, cert =
32
- payload.fetch('signature').unpack('m').first.unpack('c a128 N a*')
33
- return false unless
34
- version == 2 &&
35
- sig.size == 128 &&
36
- cert.size == cert_length &&
37
- (cert = OpenSSL::X509::Certificate.new(cert)) &&
38
- cert.verify(PUBLIC_KEY)
39
- data = [version, purchase_info].pack('ca*')
40
- cert.public_key.verify(OpenSSL::Digest::SHA1.new, sig, data)
73
+ SignatureValidation.new(signature, purchase_info).valid?
41
74
  end
42
75
 
43
76
  private
44
77
 
45
78
  def decode
46
79
  @receipt = parse_purchase_info
47
- if payload.fetch('environment', 'Production') == 'Production'
48
- @environment = :production
49
- else
50
- @environment = :sandbox
51
- end
80
+ @environment =
81
+ if payload.fetch('environment', 'Production') == 'Production'
82
+ :production
83
+ else
84
+ :sandbox
85
+ end
52
86
  end
53
87
 
54
88
  def parse_purchase_info
@@ -64,6 +98,10 @@ PUBLIC_KEY
64
98
  @purchase_info ||= payload.fetch('purchase-info').unpack('m').first
65
99
  end
66
100
 
101
+ def signature
102
+ @signature ||= payload.fetch('signature').unpack('m').first
103
+ end
104
+
67
105
  def payload
68
106
  @payload ||= parse_plist(raw_receipt)
69
107
  end
@@ -71,7 +109,7 @@ PUBLIC_KEY
71
109
  def parse_plist(contents)
72
110
  plist = CFPropertyList::List.new(data: contents)
73
111
  hash = CFPropertyList.native_types(plist.value)
74
- fail DecodingError, 'hash not found in plist' unless hash.is_a?(Hash)
112
+ raise DecodingError, 'hash not found in plist' unless hash.is_a?(Hash)
75
113
  hash
76
114
  rescue CFPlistError => e
77
115
  raise DecodingError, e.message
@@ -1,6 +1,7 @@
1
1
  require 'time'
2
2
  require 'openssl'
3
3
  require 'itunes_receipt_decoder/decode/base'
4
+ require 'itunes_receipt_decoder/public_key'
4
5
 
5
6
  ##
6
7
  # ItunesReceiptDecoder
@@ -11,18 +12,6 @@ module ItunesReceiptDecoder
11
12
  ##
12
13
  # ItunesReceiptDecoder::Decode::UnifiedReceipt
13
14
  class UnifiedReceipt < Base
14
- PUBLIC_KEY = OpenSSL::PKey::RSA.new <<-PUBLIC_KEY
15
- -----BEGIN PUBLIC KEY-----
16
- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyjhUpstWqsgkOUjpjO7s
17
- X7h/JpG8NFN6znxjgGF3ZF6lByO2Of5QLRVWWHAtfsRuwUqFPi/w3oQaoVfJr3sY
18
- /2r6FRJJFQgZrKrbKjLtlmNoUhU9jIrsv2sYleADrAF9lwVnzg6FlTdq7Qm2rmfN
19
- UWSfxlzRvFduZzWAdjakh4FuOI/YKxVOeyXYWr9Og8GN0pPVGnG1YJydM05V+RJY
20
- DIa4Fg3B5XdFjVBIuist5JSF4ejEncZopbCj/Gd+cLoCWUt3QpE5ufXN4UzvwDtI
21
- jKblIV39amq7pxY1YNLmrfNGKcnow4vpecBqYWcVsvD95Wi8Yl9uz5nd7xtj/pJl
22
- qwIDAQAB
23
- -----END PUBLIC KEY-----
24
- PUBLIC_KEY
25
-
26
15
  ##
27
16
  # ASN.1 Field types
28
17
  #
@@ -46,11 +35,11 @@ PUBLIC_KEY
46
35
  1708 => :expires_date,
47
36
  1712 => :cancellation_date,
48
37
  1711 => :web_order_line_item_id
49
- }
38
+ }.freeze
50
39
 
51
40
  TIMESTAMP_FIELDS = %i(creation_date expiration_date purchase_date
52
41
  original_purchase_date expires_date
53
- cancellation_date)
42
+ cancellation_date).freeze
54
43
 
55
44
  def style
56
45
  :unified
@@ -67,18 +56,19 @@ PUBLIC_KEY
67
56
  def signature_valid?
68
57
  serial = pkcs7.signers.first.serial.to_i
69
58
  cert = pkcs7.certificates.find { |c| c.serial.to_i == serial }
70
- cert && cert.verify(PUBLIC_KEY)
59
+ cert && cert.verify(PublicKey::V3)
71
60
  end
72
61
 
73
62
  private
74
63
 
75
64
  def decode
76
65
  @receipt = parse_app_receipt_fields(payload.value)
77
- if @receipt.fetch(:environment, 'Production') == 'Production'
78
- @environment = :production
79
- else
80
- @environment = :sandbox
81
- end
66
+ @environment =
67
+ if @receipt.fetch(:environment, 'Production') == 'Production'
68
+ :production
69
+ else
70
+ :sandbox
71
+ end
82
72
  end
83
73
 
84
74
  def parse_app_receipt_fields(fields)
@@ -0,0 +1,32 @@
1
+ require 'openssl'
2
+
3
+ ##
4
+ # ItunesReceiptDecoder
5
+ module ItunesReceiptDecoder
6
+ ##
7
+ # ItunesReceiptDecoder::PublicKey
8
+ module PublicKey
9
+ V2 = OpenSSL::PKey::RSA.new <<-PUBLIC_KEY
10
+ -----BEGIN PUBLIC KEY-----
11
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApLyvMpRDPgu8N4fNY4ny
12
+ zNm+IE1atP6HZ9Ka3hpUnaLz34fkTMuTEXigMI80QcHTvmZtR2yYuOx61cndpeTq
13
+ xnD0NdCR97PYChGZqzpiOr179FZP258kk1FQfCDVZk1m8xikE5YiFv0xp/Q5Zpv7
14
+ YmlcS5+UqEvo7FtkWhh5ihZ1Y0KkSdmMM96te9Y5BPTinQppjOtLEihLNEgHmw5Z
15
+ +R9isAOfNrhOo9N1WdTzOgXKxTM7+MAGCQiT2+dNvxHzUiylFjUV80ECzQLR/PX4
16
+ xYS9Y2qG1raZ9oauX/0D1CiKWl2vvGV00fcaw5II9BytaegCTA6VFQe8vmpvwbOt
17
+ oQIDAQAB
18
+ -----END PUBLIC KEY-----
19
+ PUBLIC_KEY
20
+ V3 = OpenSSL::PKey::RSA.new <<-PUBLIC_KEY
21
+ -----BEGIN PUBLIC KEY-----
22
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyjhUpstWqsgkOUjpjO7s
23
+ X7h/JpG8NFN6znxjgGF3ZF6lByO2Of5QLRVWWHAtfsRuwUqFPi/w3oQaoVfJr3sY
24
+ /2r6FRJJFQgZrKrbKjLtlmNoUhU9jIrsv2sYleADrAF9lwVnzg6FlTdq7Qm2rmfN
25
+ UWSfxlzRvFduZzWAdjakh4FuOI/YKxVOeyXYWr9Og8GN0pPVGnG1YJydM05V+RJY
26
+ DIa4Fg3B5XdFjVBIuist5JSF4ejEncZopbCj/Gd+cLoCWUt3QpE5ufXN4UzvwDtI
27
+ jKblIV39amq7pxY1YNLmrfNGKcnow4vpecBqYWcVsvD95Wi8Yl9uz5nd7xtj/pJl
28
+ qwIDAQAB
29
+ -----END PUBLIC KEY-----
30
+ PUBLIC_KEY
31
+ end
32
+ end
@@ -3,5 +3,5 @@
3
3
  module ItunesReceiptDecoder
4
4
  ##
5
5
  # Gem version
6
- VERSION = '0.3.0'
6
+ VERSION = '0.3.1'.freeze
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: itunes_receipt_decoder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - mbaasy.com
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-24 00:00:00.000000000 Z
11
+ date: 2016-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: CFPropertyList
@@ -30,28 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.4'
33
+ version: '11.1'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.4'
40
+ version: '11.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.3'
47
+ version: '3.4'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.3'
54
+ version: '3.4'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rubygems-tasks
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -72,42 +72,42 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0.10'
75
+ version: '0.11'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0.10'
82
+ version: '0.11'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: codeclimate-test-reporter
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.4'
89
+ version: '0.5'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.4'
96
+ version: '0.5'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0.33'
103
+ version: '0.40'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0.33'
110
+ version: '0.40'
111
111
  description: |2
112
112
  Decode iTunes OS X and iOS receipts without remote server-side validation
113
113
  by using the Apple Inc Root Certificate.
@@ -120,6 +120,7 @@ files:
120
120
  - lib/itunes_receipt_decoder/decode/base.rb
121
121
  - lib/itunes_receipt_decoder/decode/transaction_receipt.rb
122
122
  - lib/itunes_receipt_decoder/decode/unified_receipt.rb
123
+ - lib/itunes_receipt_decoder/public_key.rb
123
124
  - lib/itunes_receipt_decoder/version.rb
124
125
  homepage: https://github.com/mbaasy/itunes_receipt_decoder
125
126
  licenses:
@@ -141,9 +142,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
142
  version: '0'
142
143
  requirements: []
143
144
  rubyforge_project:
144
- rubygems_version: 2.4.6
145
+ rubygems_version: 2.6.3
145
146
  signing_key:
146
147
  specification_version: 4
147
148
  summary: Decode iTunes OS X and iOS receipts
148
149
  test_files: []
149
- has_rdoc: