Public Key Check

Check through public key validation

As in other app stores, you must add your Catappult's public key from to your backend to validate the transactions.

Get yours here: How to get my Public Key.

Adding Catappult Public-key

This section will merge a couple suggestions for adding your new public-key on your backend server when you already own a Google Public-key.

Check purchaseToken field

You can parse a purchase received on your backend and use our public-key whenever your purchaseToken contains the prefix 'catappult.inapp.purchase'.

See the snippet below for a more detailed implementation:

import base64
import json

import rsa
from rsa import PublicKey


class PublicKeyValidator:
    def __init__(self):
        pass

    def parse_public_key(self, _public_key: str) -> PublicKey:
        pem_key = self.build_pem(_public_key)
        return rsa.PublicKey.load_pkcs1_openssl_pem(pem_key.encode())

    def build_pem(self, _public_key: str) -> str:
        return '\n'.join((
            '-----BEGIN PUBLIC KEY-----',
            '\n'.join(_public_key[i:i+64] for i in range(0, len(_public_key), 64)),
            '-----END PUBLIC KEY-----'
        ))

    def validate_purchase(self, _public_key: PublicKey,
                          _receipt: str, _signature: str) -> bool:
        try:
            decoded_signature = base64.standard_b64decode(_signature)
            if rsa.verify(_receipt.encode(), decoded_signature, _public_key):
                return True
        except (rsa.VerificationError, TypeError, ValueError, BaseException):
            return False


if __name__ == "__main__":
    public_key_validator = PublicKeyValidator()
    cat_public_key = "YOUR_CATAPPULT_PUBLIC_KEY"
    google_public_key = "YOUR_GOOGLE_PUBLIC_KEY"

    incoming_receipt = """USER_PURCHASE_RECEIPT"""
    incoming_signature = "USER_PURCHASE_SIGNATURE"

    purchase_token: str = json.loads(incoming_receipt)["purchaseToken"]
    if purchase_token.startswith("catappult.inapp.purchase"):
        print("Using Catappult Public-key")
        public_key = public_key_validator.parse_public_key(cat_public_key)
        is_success = public_key_validator.validate_purchase(
            public_key, incoming_receipt, incoming_signature)
        print("Purchase status: ", is_success)
    else:
        print("Using Google Public-key")
        public_key = public_key_validator.parse_public_key(google_public_key)
        is_success = public_key_validator.validate_purchase(
            public_key, incoming_receipt, incoming_signature)
        print("Purchase status: ", is_success)

Have a list with all your public-keys

A list with all your public-keys (Catappult, Google Play, etc...) can be used to validate every future purchase.

See the snippet below for a more detailed implementation:

import base64
import json

import rsa
from rsa import PublicKey


class PublicKeyValidator:
    def __init__(self):
        pass

    def parse_public_key(self, _public_key: str) -> PublicKey:
        pem_key = self.build_pem(_public_key)
        return rsa.PublicKey.load_pkcs1_openssl_pem(pem_key.encode())

    def build_pem(self, _public_key: str) -> str:
        return '\n'.join((
            '-----BEGIN PUBLIC KEY-----',
            '\n'.join(_public_key[i:i+64] for i in range(0, len(_public_key), 64)),
            '-----END PUBLIC KEY-----'
        ))

    def validate_purchase(self, _public_key: PublicKey,
                          _receipt: str, _signature: str) -> bool:
        try:
            decoded_signature = base64.standard_b64decode(_signature)
            if rsa.verify(_receipt.encode(), decoded_signature, _public_key):
                return True
        except (rsa.VerificationError, TypeError, ValueError, BaseException):
            return False


if __name__ == "__main__":
    public_key_validator = PublicKeyValidator()
    public_keys = ["YOUR_CATAPPULT_PUBLIC_KEY", "YOUR_GOOGLE_PUBLIC_KEY"]

    incoming_receipt = """USER_PURCHASE_RECEIPT"""
    incoming_signature = "USER_PURCHASE_SIGNATURE"

    purchase_token: str = json.loads(incoming_receipt)["purchaseToken"]
    for public_key in public_keys:
        print("Checking purchase with '{}'".format(public_key))
        public_key = public_key_validator.parse_public_key(public_key)
        is_success = public_key_validator.validate_purchase(
            public_key, incoming_receipt, incoming_signature)
        if is_success:
            print("Purchase successfully validated")