itunes_receipt_decoder 0.2.3 → 0.3.0

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: 7249d3ca881c622ef2e0ccd6d94be8da200eece2
4
- data.tar.gz: ccea5b7c522881e76705920a20a6ab49a396d7ea
3
+ metadata.gz: be8ac7da532b84da681984f7e5e51e8677133d77
4
+ data.tar.gz: fc0888f8a80f019e20059535fe6e926ed5c56e40
5
5
  SHA512:
6
- metadata.gz: 812a954786a1bb1dc53677e68a8fe8494b6f8f46765d5ce8404132354680bccffc774bd2fb909e1d76e06e643493da1b4b010eb701b3e680270c91093e86b562
7
- data.tar.gz: 0887a6b967bdd98309bc052812bfee0500d3cdcec88725e8cf0f109f3e0e0ff2de186e5624bfc73ce46d68ccedf820d7cc41c4f2d9cc0f2adb767b036db21394
6
+ metadata.gz: 056453f28cb7f4b62464736c07cbdc90bfe53aa1802d371075fe418146646d11312047cbec620edea1620c4f0b1b4a80319992db6bbf63f93b28314ce3ada481
7
+ data.tar.gz: b9d31eb78fef4c3753aa19f610cf092474757bee9b01339b303e8a853a286c30405244fcea628a00bb375a9460b97c4cd9b48e3fbab4bb8b1577a8989c39ae89
@@ -1,8 +1,4 @@
1
- require 'time'
2
- require 'openssl'
3
- require 'cfpropertylist'
4
1
  require 'itunes_receipt_decoder/version'
5
- require 'itunes_receipt_decoder/decode/base'
6
2
  require 'itunes_receipt_decoder/decode/transaction_receipt'
7
3
  require 'itunes_receipt_decoder/decode/unified_receipt'
8
4
 
@@ -9,7 +9,7 @@ module ItunesReceiptDecoder
9
9
  class Base
10
10
  ##
11
11
  # The raw receipt, i.e. not base64 encoded
12
- attr_reader :raw_receipt, :receipt, :options, :style, :environment
12
+ attr_reader :raw_receipt, :receipt, :options, :environment
13
13
 
14
14
  ##
15
15
  # Initializes with a raw (base64 decoded receipt)
@@ -1,3 +1,7 @@
1
+ require 'openssl'
2
+ require 'cfpropertylist'
3
+ require 'itunes_receipt_decoder/decode/base'
4
+
1
5
  ##
2
6
  # ItunesReceiptDecoder
3
7
  module ItunesReceiptDecoder
@@ -7,9 +11,33 @@ module ItunesReceiptDecoder
7
11
  ##
8
12
  # ItunesReceiptDecoder::Decode::TransactionReceipt
9
13
  class TransactionReceipt < Base
10
- def initialize(raw_receipt, options = {})
11
- @style = :transaction
12
- super
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
25
+
26
+ def style
27
+ :transaction
28
+ end
29
+
30
+ 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)
13
41
  end
14
42
 
15
43
  private
@@ -24,16 +52,16 @@ module ItunesReceiptDecoder
24
52
  end
25
53
 
26
54
  def parse_purchase_info
27
- purchase_info.keys.each do |key|
55
+ result = parse_plist(purchase_info)
56
+ result.keys.each do |key|
28
57
  new_key = key.tr('-', '_').to_sym
29
- purchase_info[new_key] = purchase_info.delete(key)
58
+ result[new_key] = result.delete(key)
30
59
  end
31
- purchase_info
60
+ result
32
61
  end
33
62
 
34
63
  def purchase_info
35
- @purchase_info ||=
36
- parse_plist(payload.fetch('purchase-info').unpack('m').first)
64
+ @purchase_info ||= payload.fetch('purchase-info').unpack('m').first
37
65
  end
38
66
 
39
67
  def payload
@@ -1,3 +1,7 @@
1
+ require 'time'
2
+ require 'openssl'
3
+ require 'itunes_receipt_decoder/decode/base'
4
+
1
5
  ##
2
6
  # ItunesReceiptDecoder
3
7
  module ItunesReceiptDecoder
@@ -7,6 +11,18 @@ module ItunesReceiptDecoder
7
11
  ##
8
12
  # ItunesReceiptDecoder::Decode::UnifiedReceipt
9
13
  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
+
10
26
  ##
11
27
  # ASN.1 Field types
12
28
  #
@@ -15,6 +31,8 @@ module ItunesReceiptDecoder
15
31
  0 => :environment,
16
32
  2 => :bundle_id,
17
33
  3 => :application_version,
34
+ 4 => :opaque_value,
35
+ 5 => :sha1_hash,
18
36
  12 => :creation_date,
19
37
  17 => :in_app,
20
38
  19 => :original_application_version,
@@ -34,9 +52,22 @@ module ItunesReceiptDecoder
34
52
  original_purchase_date expires_date
35
53
  cancellation_date)
36
54
 
37
- def initialize(raw_receipt, options = {})
38
- @style = :unified
39
- super
55
+ def style
56
+ :unified
57
+ end
58
+
59
+ def uuid_valid?(uuid)
60
+ digest = OpenSSL::Digest::SHA1.new
61
+ digest << uuid.scan(/[0-9A-F]{2}/).map(&:hex).pack('c*')
62
+ digest << @receipt[:opaque_value]
63
+ digest << @raw_bundle_id
64
+ digest.digest == @receipt[:sha1_hash]
65
+ end
66
+
67
+ def signature_valid?
68
+ serial = pkcs7.signers.first.serial.to_i
69
+ cert = pkcs7.certificates.find { |c| c.serial.to_i == serial }
70
+ cert && cert.verify(PUBLIC_KEY)
40
71
  end
41
72
 
42
73
  private
@@ -55,7 +86,12 @@ module ItunesReceiptDecoder
55
86
  fields.each do |seq|
56
87
  type, _version, value = seq.value.map(&:value)
57
88
  next unless (field = RECEIPT_FIELDS[type.to_i])
58
- build_result(result, field, value)
89
+ if %i(opaque_value sha1_hash).include?(field)
90
+ result[field] = value
91
+ else
92
+ @raw_bundle_id = value if field == :bundle_id
93
+ build_result(result, field, value)
94
+ end
59
95
  end
60
96
  result
61
97
  end
@@ -3,5 +3,5 @@
3
3
  module ItunesReceiptDecoder
4
4
  ##
5
5
  # Gem version
6
- VERSION = '0.2.3'
6
+ VERSION = '0.3.0'
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.2.3
4
+ version: 0.3.0
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-07 00:00:00.000000000 Z
11
+ date: 2015-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: CFPropertyList