voltrue2 / in-app-purchase

A Node.js module for in-App-Purchase for iOS, Android, Amazon and Windows.
http://iap.gracenode.org
Other
1.04k stars 287 forks source link

[iOS] iap.isValidated() returns false for receipt with "Sandbox validation successful" #280

Open svzi opened 4 years ago

svzi commented 4 years ago

Hi there!

I'm trying to use this plugin to validate my in-app-purchases. For Android receipt validation my code is working as expected, but for Apple Sandbox receipts it fails, even when the verbose debug output of the plugin tells me, the the receipt has been validated successfully.

I'm using this code (simplified for demonstration purposes):

await iap.setup();
const res = await iap.validate(receipt);
if (iap.isValidated(res)) {
    // get the purchased items that have not been expired or canceled
    const options: any = {
        ignoreCanceled: true,
        ignoreExpired: true,
    };
    const purchaseDataList: any[] = iap.getPurchaseData(googleRes, options);
    if (purchaseDataList.length > 0) {
        let foundValid: boolean = false;
        purchaseDataList.forEach(purchase => {
            console.log('iap.isValidated(purchase):', iap.isValidated(purchase));
            if (iap.isValidated(purchase)) {
                // found valid receipt
                foundValid = true;
            }
        });
    }
}

This is what my console output returns when validating a sandbox receipt (Apple):

[1566490909230][VERBOSE] <Apple> Sandbox validation successful: { receipt: 
   { receipt_type: 'ProductionSandbox',
     adam_id: 0,
     app_item_id: 0,
     bundle_id: 'com.abc.xyq',
     application_version: '1.0.0',
     download_id: 0,
     version_external_identifier: 0,
     receipt_creation_date: '2019-08-22 16:20:41 Etc/GMT',
     receipt_creation_date_ms: '1566490841000',
     receipt_creation_date_pst: '2019-08-22 09:20:41 America/Los_Angeles',
     request_date: '2019-08-22 16:21:49 Etc/GMT',
     request_date_ms: '1566490909209',
     request_date_pst: '2019-08-22 09:21:49 America/Los_Angeles',
     original_purchase_date: '2013-08-01 07:00:00 Etc/GMT',
     original_purchase_date_ms: '1375340400000',
     original_purchase_date_pst: '2013-08-01 00:00:00 America/Los_Angeles',
     original_application_version: '1.0',
     in_app: [ [Object] ] },
  status: 0,
  environment: 'Sandbox',
  sandbox: true }

iap.isValidated(purchase): false

What do I need to make iap.isValidated() return true for this receipt?

Any help would be really much appreciated!

Best, Sven

voltrue2 commented 4 years ago

Hello,

iap.isValidated() expects the returned object of iap.validate().

The code below needs to be removed.

console.log('iap.isValidated(purchase):', iap.isValidated(purchase));
            if (iap.isValidated(purchase)) {
                // found valid receipt
                foundValid = true;
            }

Cheers

svzi commented 4 years ago

Just to be clear, this code would be sufficient:

await iap.setup();
const res = await iap.validate(receipt);
if (iap.isValidated(res)) {
    // found valid receipt
    foundValid = true;
}

No need to call iap.getPurchaseData(googleRes, options); and validate each of the returned objects?

voltrue2 commented 4 years ago

Hello, Yes the code you pasted above is sufficient. getPurchaseData() is just a support function that may help make your life simpler but not required.

Cheers!

svzi commented 4 years ago

Thanks a lot for clarification @voltrue2 !

svzi commented 4 years ago

Sorry, I need to bother you again @voltrue2 !

With the code I mentioned here (https://github.com/voltrue2/in-app-purchase/issues/280#issuecomment-524193545), my validation returns true for a sandbox receipt that should not be true in my opinion:

...
<Apple> Try validate against sandbox: https://sandbox.itunes.apple.com/verifyReceipt
<Apple> https://sandbox.itunes.apple.com/verifyReceipt validation response: { auto_renew_status: 0, latest_expired_receipt_info: { original_purchase_date_pst: '2019-09-10 08:30:26 America/Los_Angeles', quantity: '1', unique_vendor_identifier: 'xxx', bvrs: '1.
2019-09-25T06:50:24.042Z 92cb8113-62cb-4e8d-991b-121efcd0ea85 [1569394224042]<Apple> https://sandbox.itunes.apple.com/verifyReceipt validation response: { auto_renew_status: 0,
latest_expired_receipt_info:
{ original_purchase_date_pst: '2019-09-10 08:30:26 America/Los_Angeles',
quantity: '1',
unique_vendor_identifier: 'xxx',
bvrs: '1.2.2',
expires_date_formatted: '2019-09-19 13:41:11 Etc/GMT',
is_in_intro_offer_period: 'false',
purchase_date_ms: '1568896871000',
expires_date_formatted_pst: '2019-09-19 06:41:11 America/Los_Angeles',
is_trial_period: 'false',
item_id: 'yyy',
unique_identifier: 'zzz',
original_transaction_id: 'aaa',
subscription_group_identifier: 'bbb',
transaction_id: 'ccc',
bid: 'this.that',
web_order_line_item_id: 'ccc',
purchase_date: '2019-09-19 12:41:11 Etc/GMT',
product_id: 'ddd',
expires_date: '1568900471000',
original_purchase_date: '2019-09-10 15:30:26 Etc/GMT',
purchase_date_pst: '2019-09-19 05:41:11 America/Los_Angeles',
original_purchase_date_ms: '1568129426000' },
status: 21006,
auto_renew_product_id: 'ddd',
receipt:
{ original_purchase_date_pst: '2019-09-10 08:30:26 America/Los_Angeles',
quantity: '1',
unique_vendor_identifier: 'xxx',
bvrs: '1.2.2',
expires_date_formatted: '2019-09-19 09:41:11 Etc/GMT',
is_in_intro_offer_period: 'false',
purchase_date_ms: '1568882471000',
expires_date_formatted_pst: '2019-09-19 02:41:11 America/Los_Angeles',
is_trial_period: 'false',
item_id: 'yyy',
unique_identifier: 'zzz',
original_transaction_id: 'aaa',
subscription_group_identifier: 'bbb',
transaction_id: 'ccc',
web_order_line_item_id: 'ddd',
version_external_identifier: '0',
purchase_date: '2019-09-19 08:41:11 Etc/GMT',
product_id: 'this.that',
expires_date: '1568886071000',
original_purchase_date: '2019-09-10 15:30:26 Etc/GMT',
purchase_date_pst: '2019-09-19 01:41:11 America/Los_Angeles',
bid: 'this.that',
original_purchase_date_ms: '1568129426000' },
expiration_intent: '1',
is_in_billing_retry_period: '0' }
<Apple> Valid receipt, but has been cancelled (not expired yet)

That receipt is canceled and has expired about 6 days ago. Any idea why this receipt is reported back as valid???

Best, Sven

jayna456 commented 4 years ago

Hello @svzi , Have you resolve this issue? I am facing similar issue. I am always getting true from isValidate()

svzi commented 4 years ago

@jayna456 It probably depends on what you're trying to verify. To you validate subscriptions or simple purchases, or both?

jayna456 commented 4 years ago

Hello @svzi , I want to validate subscriptions. I figured out the problem. in getPurchaseData() I am passing ignoreExpired as true. Just removed that and problem solved..

svzi commented 4 years ago

@jayna456 👍