Module: AppleReceipt::ReceiptParser

Defined in:
lib/apple_receipt/receipt_parser.rb

Overview

ReceiptParser contains helper methods to parse receipt data structures.

Constant Summary collapse

SIGNATURE_LENGTH_MAPPING =
{
  2 => 128,
  3 => 256
}.freeze

Class Method Summary collapse

Class Method Details

.parse(input) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/apple_receipt/receipt_parser.rb', line 20

def parse(input)
  receipt_hash = NextStepParser.parse(input)

  unless Set['signature', 'purchase_info'].subset?(receipt_hash.keys.to_set)
    raise ArgumentError, 'Missing required fields'
  end

  signature_decoded = Base64.decode64(receipt_hash['signature'])
  data_decoded = Base64.decode64(receipt_hash['purchase_info'])

  version, signature, receipt_cert = read_signature(signature_decoded)
  [version, signature, receipt_cert, data_decoded]
end

.read_signature(signature_decoded) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/apple_receipt/receipt_parser.rb', line 34

def read_signature(signature_decoded)
  sig = StringIO.new(signature_decoded)
  version = sig.read(1).unpack('C').first # 8-bit unsigned (unsigned char)

  unless SIGNATURE_LENGTH_MAPPING.keys.include?(version)
    raise ArgumentError, "Unsupported receipt version: #{version}"
  end

  signature = sig.read(SIGNATURE_LENGTH_MAPPING[version])
  cert_size = sig.read(4).unpack('L>')[0] # 32-bit unsigned, big-endian
  receipt_cert = OpenSSL::X509::Certificate.new(sig.read(cert_size))

  [version, signature, receipt_cert]
end