protonlabs/ios-receipt-parser

Utility to parse Apple-issued PKCS#7 container with receipts

Installs: 19 683

Dependents: 0

Suggesters: 0

Security: 0

Stars: 1

Watchers: 2

Forks: 6

Language:HTML

v1.0.0 2020-09-01 19:18 UTC

This package is not auto-updated.

Last update: 2024-04-18 03:22:58 UTC


README

License: MIT GitHub tag (latest by date) GitHub issues GitHub pull requests GitHub branch checks state Continuous Integration

This library is forked from cthulhu/ios-receipt-parser and mantained by Proton.

Description

This library can be used to parse Apple billing receipts without calling Apple servers. The parser is built in accordance with the official Apple documentation. More information can be found at the following links:

This parser is required, in particular, when you use the latest XCode features to test your billing flow since receipts generated using this method are signed by your local special-purpose certificate and can not be validated via Apple's own servers. In all other cases you should strongly prefer to validate all receipts against Apple servers.

Installation

You can install this library via Composer:

composer install protonlabs/ios-receipt-parser

Usage

The main use case is to parse receipt generated by StoreKit locally. There is no need to validate the signatures.

<?php

use Proton\IosReceiptParser\InApp;
use Proton\IosReceiptParser\Parser;
use Proton\IosReceiptParser\Receipt;

include __DIR__ . '/vendor/autoload.php';

const RECEIPT = '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';

$receipt = (new Parser())->parseUnverified(RECEIPT);

// Just for documentation purpose
assert($receipt instanceof Receipt);

var_dump($receipt->getBundleId());

foreach ($receipt->getInApp() as $inApp) {
    // Just for documentation purpose
    assert($inApp instanceof InApp);

    var_dump("{$inApp->getQuantity()} x {$inApp->getProductIdentifier()}");
}

Verifying signatures

It is possible to verify the signatures by passing to Parser an instance of OpenSslProcessPkcs7Reader (PKCS#7 reader). At the momenr only this type of reader is implemented which requires you to:

  • install symfony/process;
  • have openssl installed in your system;
  • set your PHP configuration to allow the execution of shell scripts.
<?php

use Proton\IosReceiptParser\ASN1\OpenSslProcessPkcs7Reader;
use Proton\IosReceiptParser\Parser;

include __DIR__ . '/vendor/autoload.php';

$parser = new Parser(new OpenSslProcessPkcs7Reader());

// certificates must be PEM-encoded x.509 certificates
$receipt = $parser->parseUsingOnlyTrustedCerts(RECEIPT, CERT_OR_PATH_TO_CERT, OTHER_CERT);

var_dump($receipt->getBundleId());

The use of parseUsingOnlyTrustedCerts guarantees that the signature in PKCS#7 has been validated against one of the certificates you have provided. The certificates are considered trusted (their own signatures are not verified). That means it is strongly suggested to pass to this function only trusted certificates.

Documentation

Check out the documentation for the library here.

Code coverage

Check out the code coverage for the library here.

Contributing

All contributions are welcome. Please see this page before you get started.

License

Project License can be found here.