dotpot / InAppPy

Python In-app purchase validator for Apple AppStore and GooglePlay.
MIT License
207 stars 50 forks source link

GooglePlayValidator - unhashable type: 'slice' #78

Closed LuptonM closed 3 years ago

LuptonM commented 3 years ago

First off I have never done IAP receipt validation so have been searching for the least stressful method of implementation.

I believe my key is in the correct format but seem to be having issues

Description

I've read in an api key that is in the same format as the example. In my example its read in as a dictionary. I've also tried to read it in as a string just in case but still throws an error.

Also running the example throws a bug

Actual Behavior

validator = GooglePlayValidator(bundle_id, api_credentials) File "C:\Users\Marc\Desktop\Purchase Validation\venv\lib\site-packages\inapppy\googleplay.py", line 45, in init pem = make_pem(api_key) File "C:\Users\Marc\Desktop\Purchase Validation\venv\lib\site-packages\inapppy\googleplay.py", line 18, in make_pem return "\n".join(("-----BEGIN PUBLIC KEY-----", "\n".join(value), "-----END PUBLIC KEY-----")) File "C:\Users\Marc\Desktop\Purchase Validation\venv\lib\site-packages\inapppy\googleplay.py", line 17, in value = (public_key[i : i + 64] for i in range(0, len(public_key), 64)) # noqa: E203 TypeError: unhashable type: 'slice'

Possible Fix

Steps to Reproduce

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.

with open("service_account.json", "r") as content: api_credentials = json.load(content)

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

Context

Your Environment

ishakoktn commented 3 years ago

I also across to this problem.

Looks like the problem is occur because of wrong example in README.

GooglePlayValidator doesn't get the credentials file/json file, It requires only Public Key which has not include "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----" tags.

PS: As you now, you could extract Public Key from Private Key which is accessible in Google service account json.

omidraha commented 3 years ago

Same issue

>>> GooglePlayValidator(bundle_id, api_credentials)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/***/python3.8/site-packages/inapppy/googleplay.py", line 45, in __init__
    pem = make_pem(api_key)
  File "/***/python3.8/site-packages/inapppy/googleplay.py", line 18, in make_pem
    return "\n".join(("-----BEGIN PUBLIC KEY-----", "\n".join(value), "-----END PUBLIC KEY-----"))
  File "/***/site-packages/inapppy/googleplay.py", line 17, in <genexpr>
    value = (public_key[i : i + 64] for i in range(0, len(public_key), 64))  # noqa: E203
TypeError: unhashable type: 'slice'
omidraha commented 3 years ago

How to get api_key?

with something like this:

{
  "type": "service_account",
  "project_id": "****",
  "private_key_id": "*****",
  "private_key": "-----BEGIN PRIVATE KEY-----\\*****==\n-----END PRIVATE KEY-----\n",
  "client_email": "***.iam.gserviceaccount.com",
  "client_id": "****",
  "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/*****.iam.gserviceaccount.com"
}

I tried:

import json
from inapppy import GooglePlayValidator, InAppPyValidationError
from Crypto.PublicKey import RSA
import  base64

p = 'credentials.json'
f = open(p)
api_credentials = json.load(f)
private_key = RSA.importKey(api_credentials['private_key'])
public_key = private_key.publickey().exportKey('PEM')
public_key_b64 = base64.standard_b64encode(public_key).decode('ascii')
GooglePlayValidator(bundle_id, public_key_b64)

But i got error: PyAsn1Error:

LuptonM commented 3 years ago

So in the end I got round this as I found some Google documentation on how to use their APIs (I think it was for Google ads or something) and didn't use this package

On Thu, 12 Aug 2021, 16:33 Omid Raha, @.***> wrote:

How to get api_key?

with something like this:

{ "type": "service_account", "project_id": "", "private_key_id": "****", "private_key": "-----BEGIN PRIVATE KEY-----\==\n-----END PRIVATE KEY-----\n", "client_email": "*.iam.gserviceaccount.com", "client_id": "*", "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/.iam.gserviceaccount.com" }

I tried:

import jsonfrom inapppy import GooglePlayValidator, InAppPyValidationErrorfrom Crypto.PublicKey import RSAimport base64 p = 'credentials.json'f = open(p)api_credentials = json.load(f)private_key = RSA.importKey(api_credentials['private_key'])public_key = private_key.publickey().exportKey('PEM')public_key_b64 = base64.standard_b64encode(public_key).decode('ascii')GooglePlayValidator(bundle_id, public_key_b64)

But i got error: PyAsn1Error:

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/dotpot/InAppPy/issues/78#issuecomment-897739436, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANO5LJYY7CKMQJAD3TFXOY3T4PSWNANCNFSM43TP6HUA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email .

ackviz commented 1 year ago

Hello,

since the error README is still misleading here is what you are looking for

from inapppy import GooglePlayVerifier, errors

GOOGLE_BUNDLE_ID = 'com.xx.xx'
GOOGLE_SERVICE_ACCOUNT_KEY_FILE = './file.json'

verifier = GooglePlayVerifier(GOOGLE_BUNDLE_ID, GOOGLE_SERVICE_ACCOUNT_KEY_FILE)