README.md in apple_receipt-0.1.1 vs README.md in apple_receipt-0.2.0

- old
+ new

@@ -1,10 +1,17 @@ -# AppleReceipt +# Apple Receipt +[![Gem Version](https://badge.fury.io/rb/apple_receipt.svg)](https://badge.fury.io/rb/apple_receipt) [![Build Status](https://travis-ci.org/koenrh/apple_receipt.svg?branch=master)](https://travis-ci.org/koenrh/apple_receipt) +[![Dependency Status](https://beta.gemnasium.com/badges/github.com/koenrh/apple_receipt.svg)](https://beta.gemnasium.com/projects/github.com/koenrh/apple_receipt) -This gem allows you to to locally/cryptographically verify Apple receipts. +This gem allows you to read and verify Apple receipts. It was originally built +to locally (server-side) verify the validity of receipts that are embedded in +[Status Update Notifications](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Subscriptions.html#//apple_ref/doc/uid/TP40008267-CH7-SW13). +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) +App Store receipts you might be familiar with, which are [PKCS #7](https://tools.ietf.org/html/rfc2315) +containers with a payload (receipt data) encoded using [ASN.1](https://www.itu.int/itu-t/recommendations/rec.aspx?rec=X.690). ## Installation Add this line to your application's Gemfile: @@ -23,48 +30,83 @@ ## Usage ```ruby require 'apple_receipt' -# check validity (certificate chain, and signature) +# Check receipt's validity (certificate chain, and signature) receipt_raw = File.read('./receipt.txt') receipt = AppleReceipt::Receipt.new(receipt_raw) receipt.valid? # => true -# read purchase info +# Read receipt's data (data in example shortened for brevity) receipt.purchase_info -# => {"original-purchase-date-pst"=>"2017-12-23 09:03:53 America/Los_Angeles", -# "quantity"=>"1", -# "unique-vendor-identifier"=>"D895D8DB-AEDF-4530-B7E5-E0C9A9A394B6", -# "original-purchase-date-ms"=>"1514048633000", -# "expires-date-formatted"=>"2018-01-23 17:03:44 Etc/GMT", -# "is-in-intro-offer-period"=>"false", -# "purchase-date-ms"=>"1514048624000", -# "expires-date-formatted-pst"=>"2018-01-23 09:03:44 America/Los_Angeles", -# "is-trial-period"=>"false", -# "item-id"=>"1190360447", -# "unique-identifier"=>"fed543dc24065fa2ab23ef08b0b44c0a0c9ed375", -# "original-transaction-id"=>"160000408504141", -# "expires-date"=>"1516727024000", -# "app-item-id"=>"947936149", -# "transaction-id"=>"160000408504141", -# "bvrs"=>"7000", -# "web-order-line-item-id"=>"160000091314729", -# "version-external-identifier"=>"825366855", -# "bid"=>"com.foo.bar", -# "product-id"=>"com.foo.bar.monthly", -# "purchase-date"=>"2017-12-23 17:03:44 Etc/GMT", -# "purchase-date-pst"=>"2017-12-23 09:03:44 America/Los_Angeles", -# "original-purchase-date"=>"2017-12-23 17:03:53 Etc/GMT"} +# => { +# "quantity"=>"1", +# "expires-date-formatted"=>"2018-01-23 17:03:44 Etc/GMT", +# "is-in-intro-offer-period"=>"false", +# "is-trial-period"=>"false", +# "item-id"=>"1190360447", +# "app-item-id"=>"947936149", +# "transaction-id"=>"160000408504141", +# "web-order-line-item-id"=>"160000011000001", +# "bid"=>"com.foo.bar", +# "product-id"=>"com.foo.bar.monthly", +# "purchase-date"=>"2017-12-23 17:03:44 Etc/GMT", +# "original-purchase-date"=>"2017-12-23 17:03:53 Etc/GMT" +# } ``` +## Apple receipts + +A receipt is encoded as base64, and is formatted as a [NeXTSTEP](https://en.wikipedia.org/wiki/Property_list#NeXTSTEP) +dictionary: + +``` +{ + "signature" = "[base64-encoded signature]"; + "purchase-info" = "[base64-encoded purchase data]"; + "pod" = "[integer]"; + "signing-status" = "0"; +} +``` + +### Signature + +The `signature` entry contains base64-encoded binary data, which has the following +layout: + +- **1 byte** - Receipt version (e.g. version 3). +- **128 bytes** (version 2) or **256 bytes** (version 3) - Signature. +- **4 bytes** - Length (in number of bytes) of the certificate. +- **N bytes** - DER-encoded certificate. + +The version 2 and 3 receipt certificates are signed, respectively, by: + +- **Apple iTunes Store Certification Authority** (version 2) + - Serial: 26 (`0x1a`) + - Subject: `C=US, O=Apple Inc., OU=Apple Certification Authority, CN=Apple iTunes Store Certification Authority` +- **Apple Worldwide Developer Relations Certification Authority** (version 3) + - Serial: 134752589830791184 (`0x1debcc4396da010`) + - Subject: `C=US, O=Apple Inc., OU=Apple Worldwide Developer Relations, CN=Apple Worldwide Developer Relations Certification Authority` + +Both certificates chain up to: + +- **Apple Root CA** + - Serial: 2 (`0x2`) + - Subject: `C=US, O=Apple Inc., OU=Apple Certification Authority, CN=Apple Root CA` + +### Purchase info + +The `purchase-info` entry contains a base64-encoded NeXTSTEP dictionary that contains +the actual receipt data (purchase info). + ## Contributing Bug reports and pull requests are welcome on [GitHub](https://github.com/koenrh/apple_receipt). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://www.contributor-covenant.org) code of conduct. ## License -The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). +The gem is available as open source under the terms of the [ISC License](https://opensource.org/licenses/ISC).