Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

inapppy

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

inapppy

In-app purchase validation library for Apple AppStore and GooglePlay.

  • 2.5.2
  • PyPI
  • Socket score

Maintainers
1

InAppPy

|travis| |pypi| |downloads|

.. |travis| image:: https://travis-ci.org/dotpot/InAppPy.svg?branch=master :target: https://travis-ci.org/dotpot/InAppPy .. |pypi| image:: https://badge.fury.io/py/inapppy.svg :target: https://badge.fury.io/py/inapppy .. |downloads| image:: https://img.shields.io/pypi/dm/inapppy.svg :target: https://pypi.python.org/pypi/inapppy

Table of contents

  1. Introduction

  2. Installation

  3. Google Play (receipt + signature)

  4. Google Play (verification)

  5. Google Play (verification with result)

  6. App Store (receipt + using optional shared-secret)

  7. App Store Response (validation_result / raw_response) example

  8. App Store, asyncio version (available in the inapppy.asyncio package)

  9. Development

  10. Donate

  11. Introduction ===============

In-app purchase validation library for Apple AppStore and GooglePlay (App Store validator have async support!). Works on python3.6+

  1. Installation =============== ::

    pip install inapppy

  2. Google Play (validates receipt against provided signature using RSA) =========================================================================== .. code:: python

    from inapppy import GooglePlayValidator, InAppPyValidationError

    bundle_id = 'com.yourcompany.yourapp' api_key = 'API key from the developer console' validator = GooglePlayValidator(bundle_id, api_key)

    try: # receipt means androidData in result of purchase # signature means signatureAndroid in result of purchase validation_result = validator.validate('receipt', 'signature') except InAppPyValidationError: # handle validation error pass

An additional example showing how to authenticate using dict credentials instead of loading from a file

.. code:: python

import json
from inapppy import GooglePlayValidator, InAppPyValidationError


bundle_id = 'com.yourcompany.yourapp'
# Avoid hard-coding credential data in your code. This is just an example. 
api_credentials = json.loads('{'
                             '   "type": "service_account",'
                             '   "project_id": "xxxxxxx",'
                             '   "private_key_id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",'
                             '   "private_key": "-----BEGIN PRIVATE KEY-----\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXX==\n-----END PRIVATE KEY-----\n",'
                             '   "client_email": "XXXXXXXXX@XXXXXXXX.XXX",'
                             '   "client_id": "XXXXXXXXXXXXXXXXXX",'
                             '   "auth_uri": "https://accounts.google.com/o/oauth2/auth",'
                             '   "token_uri": "https://oauth2.googleapis.com/token",'
                             '   "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",'
                             '   "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/XXXXXXXXXXXXXXXXX.iam.gserviceaccount.com"'
                             ' }')
validator = GooglePlayValidator(bundle_id, api_credentials)

try:
    # receipt means `androidData` in result of purchase
    # signature means `signatureAndroid` in result of purchase
    validation_result = validator.validate('receipt', 'signature')
except InAppPyValidationError:
    # handle validation error
    pass

4. Google Play verification

.. code:: python

from inapppy import GooglePlayVerifier, errors


def google_validator(receipt):
    """
    Accepts receipt, validates in Google.
    """
    purchase_token = receipt['purchaseToken']
    product_sku = receipt['productId']
    verifier = GooglePlayVerifier(
        GOOGLE_BUNDLE_ID,
        GOOGLE_SERVICE_ACCOUNT_KEY_FILE,
    )
    response = {'valid': False, 'transactions': []}
    try:
        result = verifier.verify(
            purchase_token,
            product_sku,
			is_subscription=True
        )
        response['valid'] = True
        response['transactions'].append(
            (result['orderId'], product_sku)
        )
    except errors.GoogleError as exc:
        logging.error('Purchase validation failed {}'.format(exc))
    return response

5. Google Play verification (with result)

Alternative to .verify method, instead of raising an error result class will be returned.

.. code:: python

from inapppy import GooglePlayVerifier, errors


def google_validator(receipt):
    """
    Accepts receipt, validates in Google.
    """
    purchase_token = receipt['purchaseToken']
    product_sku = receipt['productId']
    verifier = GooglePlayVerifier(
        GOOGLE_BUNDLE_ID,
        GOOGLE_SERVICE_ACCOUNT_KEY_FILE,
    )
    response = {'valid': False, 'transactions': []}

    result = verifier.verify_with_result(
        purchase_token,
        product_sku,
        is_subscription=True
    )

    # result contains data
    raw_response = result.raw_response
    is_canceled = result.is_canceled
    is_expired = result.is_expired

    return result

6. App Store (validates receipt using optional shared-secret against iTunes service)

.. code:: python

from inapppy import AppStoreValidator, InAppPyValidationError


bundle_id = 'com.yourcompany.yourapp'
auto_retry_wrong_env_request=False # if True, automatically query sandbox endpoint if
                                   # validation fails on production endpoint
validator = AppStoreValidator(bundle_id, auto_retry_wrong_env_request=auto_retry_wrong_env_request)

try:
    exclude_old_transactions=False # if True, include only the latest renewal transaction
    validation_result = validator.validate('receipt', 'optional-shared-secret', exclude_old_transactions=exclude_old_transactions)
except InAppPyValidationError as ex:
    # handle validation error
    response_from_apple = ex.raw_response  # contains actual response from AppStore service.
    pass

7. App Store Response (validation_result / raw_response) example

.. code:: json

{
    "latest_receipt": "MIIbngYJKoZIhvcNAQcCoIIbj...",
    "status": 0,
    "receipt": {
        "download_id": 0,
        "receipt_creation_date_ms": "1486371475000",
        "application_version": "2",
        "app_item_id": 0,
        "receipt_creation_date": "2017-02-06 08:57:55 Etc/GMT",
        "original_purchase_date": "2013-08-01 07:00:00 Etc/GMT",
        "request_date_pst": "2017-02-06 04:41:09 America/Los_Angeles",
        "original_application_version": "1.0",
        "original_purchase_date_pst": "2013-08-01 00:00:00 America/Los_Angeles",
        "request_date_ms": "1486384869996",
        "bundle_id": "com.yourcompany.yourapp",
        "request_date": "2017-02-06 12:41:09 Etc/GMT",
        "original_purchase_date_ms": "1375340400000",
        "in_app": [{
            "purchase_date_ms": "1486371474000",
            "web_order_line_item_id": "1000000034281189",
            "original_purchase_date_ms": "1486371475000",
            "original_purchase_date": "2017-02-06 08:57:55 Etc/GMT",
            "expires_date_pst": "2017-02-06 01:00:54 America/Los_Angeles",
            "original_purchase_date_pst": "2017-02-06 00:57:55 America/Los_Angeles",
            "purchase_date_pst": "2017-02-06 00:57:54 America/Los_Angeles",
            "expires_date_ms": "1486371654000",
            "expires_date": "2017-02-06 09:00:54 Etc/GMT",
            "original_transaction_id": "1000000271014363",
            "purchase_date": "2017-02-06 08:57:54 Etc/GMT",
            "quantity": "1",
            "is_trial_period": "false",
            "product_id": "com.yourcompany.yourapp",
            "transaction_id": "1000000271014363"
        }],
        "version_external_identifier": 0,
        "receipt_creation_date_pst": "2017-02-06 00:57:55 America/Los_Angeles",
        "adam_id": 0,
        "receipt_type": "ProductionSandbox"
    },
    "latest_receipt_info": [{
            "purchase_date_ms": "1486371474000",
            "web_order_line_item_id": "1000000034281189",
            "original_purchase_date_ms": "1486371475000",
            "original_purchase_date": "2017-02-06 08:57:55 Etc/GMT",
            "expires_date_pst": "2017-02-06 01:00:54 America/Los_Angeles",
            "original_purchase_date_pst": "2017-02-06 00:57:55 America/Los_Angeles",
            "purchase_date_pst": "2017-02-06 00:57:54 America/Los_Angeles",
            "expires_date_ms": "1486371654000",
            "expires_date": "2017-02-06 09:00:54 Etc/GMT",
            "original_transaction_id": "1000000271014363",
            "purchase_date": "2017-02-06 08:57:54 Etc/GMT",
            "quantity": "1",
            "is_trial_period": "true",
            "product_id": "com.yourcompany.yourapp",
            "transaction_id": "1000000271014363"
        }, {
            "purchase_date_ms": "1486371719000",
            "web_order_line_item_id": "1000000034281190",
            "original_purchase_date_ms": "1486371720000",
            "original_purchase_date": "2017-02-06 09:02:00 Etc/GMT",
            "expires_date_pst": "2017-02-06 01:06:59 America/Los_Angeles",
            "original_purchase_date_pst": "2017-02-06 01:02:00 America/Los_Angeles",
            "purchase_date_pst": "2017-02-06 01:01:59 America/Los_Angeles",
            "expires_date_ms": "1486372019000",
            "expires_date": "2017-02-06 09:06:59 Etc/GMT",
            "original_transaction_id": "1000000271014363",
            "purchase_date": "2017-02-06 09:01:59 Etc/GMT",
            "quantity": "1",
            "is_trial_period": "false",
            "product_id": "com.yourcompany.yourapp",
            "transaction_id": "1000000271016119"
        }],
    "environment": "Sandbox"
}

8. App Store, asyncio version (available in the inapppy.asyncio package)

.. code:: python

from inapppy import InAppPyValidationError
from inapppy.asyncio import AppStoreValidator


bundle_id = 'com.yourcompany.yourapp'
auto_retry_wrong_env_request=False # if True, automatically query sandbox endpoint if
                                   # validation fails on production endpoint
validator = AppStoreValidator(bundle_id, auto_retry_wrong_env_request=auto_retry_wrong_env_request)

try:
    exclude_old_transactions=False # if True, include only the latest renewal transaction
    validation_result = await validator.validate('receipt', 'optional-shared-secret', exclude_old_transactions=exclude_old_transactions)
except InAppPyValidationError as ex:
    # handle validation error
    response_from_apple = ex.raw_response  # contains actual response from AppStore service.
    pass

9. Development

.. code:: bash

# run checks and tests
tox

# setup project
make setup

# check for lint errors
make lint

# run tests
make test

# run black
make black

10. Donate

You can support development of this project by buying me a coffee ;)

+------+--------------------------------------------+ | Coin | Wallet | +======+============================================+ | EUR | https://paypal.me/LukasSalkauskas | +------+--------------------------------------------+ | DOGE | DGjSG3T6g9h2k6iSku7mtKCynCpmwowpyN | +------+--------------------------------------------+ | BTC | 1LZAiWmLYzZae4hq3ai9hFYD3e3qcwjDsU | +------+--------------------------------------------+ | ETH | 0xD62245986345130edE10e4b545fF577Bd5BaE3E4 | +------+--------------------------------------------+

Keywords

FAQs


Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc