Giter VIP home page Giter VIP logo

in-app-purchase's People

Contributors

3mini avatar baranpirincal avatar bhallionohbibi avatar chad3814 avatar containmentbreach avatar dependabot[bot] avatar electricjesus avatar ember-max avatar embertrev avatar faust64 avatar gastonelhordoy avatar jgiffard avatar joelfernandes19 avatar kpotehin avatar lfcgomes avatar markshust avatar mathieudutour avatar mooncha avatar pcg92 avatar radixdev avatar raufdean avatar superandrew213 avatar timmliu avatar ungripped avatar voltrue2 avatar whithang avatar williamchong avatar yanick avatar yringel avatar znegva avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

in-app-purchase's Issues

autoRenewing

hi @voltrue2, thank you for creating this module this really help us ( with my team ) to work stuff related to apple and google in server to server approach. I just notice something on the following areas

var iap = require('in-app-purchase');
iap.config({
'googlePublicKeyStrSandBox': "public-key-here",
'googlePublicKeyStrLive': "public-key-here"
})

  1. When setting config :
    a. setting both the sandbox and live keys must always be the case? or it can be sandbox only or live key only?
  2. Im not really sure if the this due to this module or the google itself.
    Here is the siatuation :
    In our payment merchant center ( where all the orders are listed ), the order is cancelled already by the user ( android user that bought the service ) and i can confirmed also that the order is cancelled on the PAYMENT MERCHANT CENTER but when getting the response from iap.validate i got this object {
    orderId: 'GPA.xxxx-xxxx-xxxx-xxxxx',
    packageName: 'xxx.xxxxxxxxxx.xxxx',
    productId: 'xxxxx',
    purchaseTime: 1445238298902,
    purchaseState: 0,
    purchaseToken: 'longest-string-here',
    autoRenewing: true,
    status: 0,
    service: 'google'
    }
    this is subscription type of product billing period of 1 month.

based on google docs: http://developer.android.com/google/play/billing/billing_reference.html#purchase-data-table ( table 4 reference )

autoRenewing should be false,
purchaseState: 1,

Am i right?

Upgarde and Downgrade Susbcription

Hi,

We are implementing inapp autoreneable subscription in which we want only one subscription remains at a time. We want to implement upgrade and downgrade subscription?Do you have any idea about implementation of it?

Failed to validate purchase in Android

I put my receipt and signature in database. And then I took both from database and android public key from play developer console.
Using your module, on nodejs code I created receipt to validate using below code:

var receipt = { data: JSON.stringify(receipt_val).replace(///g, '/'), signature:iap_response[0].result[0].signature};

Below is Receipt:

var receipt= { data: '{"packageName":"com.utillix.utillixapp1","productId":"praveen_test","purchaseTime":146
3582360560,"purchaseState":"0","purchaseToken":"ohdbahlifnbfoelidfknfakp.AO-J1OxdAXy9EKF7uJT8Gg
g9YUcCvx-Lk7_zZFc4s9eLijoBPvv_uG3i5WDsb8TDIjS6-U-P1Qg-oFMDD7BhzdzXpYSlwld5mkSRr6moW8nG_I4D7TNV1
paMGM2esWumQWG-4tbcnsQo","autoRenewing":false}',
signature: 'UhkS1bqFWD+UK3/3TnQ5/66YnW91FCe0hnSQtqegXb0rGPkAUzpmGq/P/Bh9nD9SE9Cvm22k/VBeI06hc
adlusplA4mwtXt9UN9xiSNOSmTnPhi4/NtZdDCFo3nGNrmL3UftEKdoHfAMvQZGUJ9rJGraI7kVku3etEAG16WY2i3Ymg8Z
fMD3c0bbgla7zmCKNc/jlvOFRieUxGGGiGyzyvH+HOLHijNZzalqwDc11FfFVnS6estETKj3YvZ+lbR9Dk/bHBZ1Zbme5lm
sgTIM9IR4QYSxXnKpvu64MSjcAwiyjgEonxJR8HNFvHDVX2EvVVCHDEi0qXIs48GjLazALQ==' }

Below is our Android Public Key

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqNUCAUHQltDpsrsos+Ma
jFU3mgffZ8ir6uK/kgkm04ALUgaT1zQsfSnEaHuvjbr96mpwJfZ4N5RWmyB1tHfh
zAvHPMTs+IB2rdReMFZ1cc4C3ZVqSf7ADb+44DRuPkHwRg0hJ6+W8zCqh9ULH6WY
ywfPsWsqtmIoJ7QpUwlfwbMApLJwaf65uEHjh0S4JQH9His5OR76ozxB2sFb6BP/
d2mjdHkRjUXKPpI5/oLFWwGpfLkWg0Novozf2ZmwturdMxi/t3+tl3IRSaLYF4DW
nlsHwgH36UxC1/xWkHBSoPQuRGI6PddRzhdIWk5kbdiQXpbDVEraPhy0YPofda6t
YQIDAQAB

I put some console.log in validatePublicKey() on google.js to test. When it goes to verify function it returns false. and I always get error "Error: failed to validate purchase".
can I know where I am doing wrong?

async.waterfall is not a function

When using the Google validation process, receive get this error:

TypeError: async.waterfall is not a function
    at checkSubscriptionStatus (/mnt/app/node_modules/in-app-purchase/lib/google.js:286:8)
    at /mnt/app/node_modules/in-app-purchase/lib/google.js:157:3
    at validatePublicKey (/mnt/app/node_modules/in-app-purchase/lib/google.js:315:10)
    at module.exports.validatePurchase (/mnt/app/node_modules/in-app-purchase/lib/google.js:139:2)
    at Object.module.exports.validate (/mnt/app/node_modules/in-app-purchase/index.js:53:2)
    at /mnt/app/index.js:664:21
    at /mnt/app/node_modules/in-app-purchase/lib/async.js:60:5
    at Object.module.exports.setup (/mnt/app/node_modules/in-app-purchase/lib/amazon.js:43:10)
    at /mnt/app/node_modules/in-app-purchase/index.js:30:11
    at iterator (/mnt/app/node_modules/in-app-purchase/lib/async.js:54:3)

This seems to be because the async library is not actually used. Instead a custom async file is used that does not have the waterfall method.

Here is the problem code at Line 286 of google.js:

async.waterfall(tasks, done);

The custom async module at https://github.com/voltrue2/in-app-purchase/blob/develop/lib/async.js does not have a method named waterfall.

Readme Example Typo

Hi, you have a small typo in your Readme explanation.

In the part you explain the text below, instead of

ignoreExpired: true

you write:

ignoreExipred: true

Example For Ignoring Expired Items:

iap.setup(function (error) {
    if (error) {
        // handle error properly here
    }
    iap.validate(iap.APPLE, receipt, function (error, response) {
        if (error) {
            // oh no error...
        }
        if (iap.isValidated(response)) {
            // get the purchased items that have not been expired ONLY
            var options = {
                ignoreExipred: true
            };
            var purchaseDataList = iap.getPurchaseData(response, options);
        }
    });
});

The purchase data structure is different for Google

Google receipt doesn't contain transactionId. Now the corresponding field is orderId.
E.g.
service: 'google' } [ { orderId: 'GPA.1318-xxx-xxx-',
2016-06-02T19:48:25.054Z pid:2080 worker:3 productId: 'xxxx',
2016-06-02T19:48:25.054Z pid:2080 worker:3 purchaseDate: 1464896898088,
2016-06-02T19:48:25.054Z pid:2080 worker:3 quantity: 1 } ]

Use config var instead of file for googlePublicKeyPath?

We're using Heroku for an open source project. To use googlePublicKeyPath, we'll need to create a private branch for the deployment managers (since we don't want to leak the key). The deployment workflow then entails rebasing master=>private with that one key commit on HEAD, and force-pushing; devs would need to check with each other, etc - slight PITA

Anyway! What I'm wondering is, any chance of using a environment var instead of a file? Since the key is just a string, it'd fit into an env var (via heroku config:set GOOGLE_PUBLIC_BLA=...).

Actually.. just realized, it's a public key - maybe that's ok to put in the public repo?

Android receipt validation always return false

I put my receipt direct into nodejs code to test.
And validate function always returns false.

I follow these steps:

Copy android public key, (from google play console) in two files named "iap-live" and "iap-sandbox" like this:

MIIBIjANqhkiG98AMIIBCgKCAQEAmhqid8hOo7UZNa9dSsssvmq6LE/+LDc5+hirTuk7ZOqPo4fAqQk045SFulIdrlt+ZWsHjFokmM8zDEpKhIGxLjT/OPEm9so9CC6xYO2HH35sbErDFFr9QxGyGYSaeZBOCrAkjaHn1uCNP0qmPvqz7JHToGEsYoOUNln1JpIuO7xXKKB62hgsQ9KfZQIDAQAB

Using a test user on android, I made a purchase (with no real charge) with my Unity3D app, and saved data and signature on txt files.

Using your module, on nodejs code I created this receipt object to validate:

var receipt = {
data : '{"orderId":"GPA.1352-1234-2530-92420","packageName":"com.jrtm.TestIAP3","productId":"ide","purchaseTime":1457100623859,"purchaseState":0,"purchaseToken":"jpjobppalfgdjgiglkpimfai.AO-J1OxF12taoYOPZMN6EK-uvr-bOqJ-NNSlk2wdFyfCH3EtiBXfm_Vd81cdQX4WP1xKjivx7"}',
signature : 'Edg4mfzB8/14FDtABNeNfHTiCbWfVO6ANfitBjzQ/E0IAHBTSZF2NvHPuf0kVYjdrj7gfL+jHGq2Nq0AEfV/3dvQuck+750uLMRaeZ0djxeiNLji5VQYyM78q+2mYQrvUIijD0NYQRZdPeoYqjgcZC4ZaaIwH5tbPOE9kBzcfZf0SOo+WxnLSxRLl8C3t/U3UQkMzCjUscMK4DVQPZXohKCCQbenIDs9ey5wBHtK8MeTXuPcTMWixx+demOlEk6P6zG//JqQ7LRdDGvSb/4rkRMctrklUCudRGwqagbNUH84l7e1FBcUjzqtMeLppretXIRg50/eV7YowP8hXDB8JA=='
};

I put a few console.log() inside your function validatePublicKey() on google.js file to test if my data is ok at this point. Everything's ok. Just public key appears with some string before and after:

-----BEGIN PUBLIC KEY-----
MIIBIjANqhkiG98AMIIBCgKCAQEAmhqid8hOo7UZNa9dSsssvmq6LE/+LDc5+hirTuk7ZOqPo4fAqQk045SFulIdrlt+ZWsHjFokmM8zDEpKhIGxLjT/OPEm9so9CC6xYO2HH35sbErDFFr9QxGyGYSaeZBOCrAkjaHn1uCNP0qmPvqz7JHToGEsYoOUNln1JpIuO7xXKKB62hgsQ9KfZQIDAQAB
-----END PUBLIC KEY-----

Your module always says "Error: failed to validate purchase".

What am I doing wrong?

Google In-App Purchase Not Working

Hey there,

I'm not sure why but receipts aren't being validated for the Play Store.

Here's the input received from verbose logging:

[1469316960981][VERBOSE] <Google> Validate this: { data: 
   { developerPayload: 'inapp:plus.365:94038a0e-75cd-4ff1-8fd0-b7641d6c9809',
     packageName: 'com.edlifeapp',
     productId: 'plus.365',
     purchaseState: 0,
     purchaseTime: 1469015574292,
     purchaseToken: 'apllonnighbdcbhlnpcifgdm.AO-J1OxDjBnM7W80uIXns5dmR7VDItUGLLXe8Y_HiBhL8Hj8DhRDakP7p6nJ7y5kVUFKrr0UCbJkv8i1JZPkjMY1GQ_EMmuLxusKClZ3eVGn6iiFJ2-iMFM' },
  signature: 'OrriuTrGZrNTDL54nGV2g9JD26RQg+scavdxS5OcfBJZYmrOnxL71FUslYCyr04MvHIwJd/6bvd7x3T2oLo /OXjG/EdaV1+OhR7NtG71HMjTsrbKCKs7x4oeS1siqVMRA4oLRkf2201Z2HOOyldT1Par2VsvIS05rK4OKOSIZJY+J7VqjC SRfbohK67KBELMv85Gsl3DyDflYPIOxheshNN8g03YLhj+DOPaPQiQfBbjp/B6A2L+1kdjiKYpBDN4HtO/fGQm3rBSDoh53 BDX1r8cot2BvLR00ZV4MSrRPmFtoUL70VNcWMiC4+x7RcZX3rM7ULLjGAco/H0zSOoLTA==' }
[1469316960983][VERBOSE] <Google> Auto stringified receipt data: {"developerPayload":"inapp:plus.365:94038a0e-75cd-4ff1-8fd0-b7641d6c9809","packageName":"com.edlifeapp","productId":"plus.365","purchaseState":0,"purchaseTime":1469015574292,"purchaseToken":"apllonnighbdcbhlnpcifgdm.AO-J1OxDjBnM7W80uIXns5dmR7VDItUGLLXe8Y_HiBhL8Hj8DhRDakP7p6nJ7y5kVUFKrr0UCbJkv8i1JZPkjMY1GQ_EMmuLxusKClZ3eVGn6iiFJ2-iMFM"}
[1469316960983][VERBOSE] <Google> Try validate against live public key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnBXCRv2DCEchsOw783WPBCjud/Wf3Mit5s8MACg5LQu1cf3ITtMS0246UVU77t6z71PscfIurWZRkmSvo8MQyF4zjC2npgADMKZLHHfPhLFn3odVqLjbihDrVSD4M9Riqh+r73QBnlKVD/04gK08r6O1q1sCqNqJWSK12EHjaSiIl0tizNuJ3XAqnlhjKk39uomwkcNrN4A/H+E76HiRtftfOsanFbBTSl/Mgxv65X89U69gL9lp2YMv+OZZwMJ75vHrPLxWx7M6d95f9fpOvPtsJ4pHTEakKdT8yf5dwHKGmzODa+xBMk1C9aTK19h5MdT0OQmsjYrF5jKtfETN4QIDAQAB
[1469316960983][VERBOSE] <Google> Failed against live public key: [Error: failed to validate purchase]
[1469316960984][VERBOSE] <Google> Try validate against sandbox public key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnBXCRv2DCEchsOw783WPBCjud/Wf3Mit5s8MACg5LQu1cf3ITtMS0246UVU77t6z71PscfIurWZRkmSvo8MQyF4zjC2npgADMKZLHHfPhLFn3odVqLjbihDrVSD4M9Riqh+r73QBnlKVD/04gK08r6O1q1sCqNqJWSK12EHjaSiIl0tizNuJ3XAqnlhjKk39uomwkcNrN4A/H+E76HiRtftfOsanFbBTSl/Mgxv65X89U69gL9lp2YMv+OZZwMJ75vHrPLxWx7M6d95f9fpOvPtsJ4pHTEakKdT8yf5dwHKGmzODa+xBMk1C9aTK19h5MdT0OQmsjYrF5jKtfETN4QIDAQAB
[1469316960984][VERBOSE] <Google> Failed against sandbox public key: [Error: failed to validate purchase]

Currently sending the following through:

{"data":{"packageName":"com.edlifeapp","productId":"plus.365","purchaseTime":1469015574292,"purchaseState":0,"developerPayload":"inapp:plus.365:94038a0e-75cd-4ff1-8fd0-b7641d6c9809","purchaseToken":"apllonnighbdcbhlnpcifgdm.AO-J1OxDjBnM7W80uIXns5dmR7VDItUGLLXe8Y_HiBhL8Hj8DhRDakP7p6nJ7y5kVUFKrr0UCbJkv8i1JZPkjMY1GQ_EMmuLxusKClZ3eVGn6iiFJ2-iMFM" },"signature":"OrriuTrGZrNTDL54nGV2g9JD26RQg+scavdxS5OcfBJZYmrOnxL71FUslYCyr04MvHIwJd/6bvd7x3T2oLo/OXjG/EdaV1+OhR7NtG71HMjTsrbKCKs7x4oeS1siqVMRA4oLRkf2201Z2HOOyldT1Par2VsvIS05rK4OKOSIZJY+J7VqjCSRfbohK67KBELMv85Gsl3DyDflYPIOxheshNN8g03YLhj+DOPaPQiQfBbjp/B6A2L+1kdjiKYpBDN4HtO/fGQm3rBSDoh53 BDX1r8cot2BvLR00ZV4MSrRPmFtoUL70VNcWMiC4+x7RcZX3rM7ULLjGAco/H0zSOoLTA==" }

Public Key string definition:

iap.config({
    verbose: true,
    googlePublicKeyStrSandbox: "MIIBIjANB...",
        googlePublicKeyStrLive: "MIIBIjANB..."
});

Any ideas?

Google module not working

[Receipt]

{"data": {"packageName":"com.skyredpepper.zzactalkandroid","productId":"point_1000","purchaseTime":1475214245609,"purchaseState":0,"purchaseToken":"oddidiboidodlmboahbpfgjg.AO-J1Oz4nr73R6ggq5ITwd1BYQeo7NXNTVehPsAiqeu9AuaEMaXc6OKJomOU85lbtuEGkJsFPeYlQS4Tbc9qluOvEcU1js3n6mC99FuOnpKuhCE-4BPecgSOI28_W_djaNmxIY_2zN_M"},"signature":"fi9QIEpo+NOP37L+oweMiO0tcTVZiMsuu62G7ARgUPeEMO4aoZFAzGLkQzhyi+A45VNvOnTcXvVuwavcpjI7tgGyDUxyKIt6Z9wub3RX1WkizKM9OimMBEZh0yGW883pYqSyDed5ZvJ9nMMeBZ47bEO0HA73h8k405e/ambf/6zUL6WNs7VeedUdcf/g9PESfIK+O64MJ2AXaLifm0DE5bBFYXrT+GMPX5Bv/Yi/H8eDQGBxAcNTZEo2JaLhlC6YM0DmBSOW1/f/woiXRH7mJPZNoLOJn+DyZmh4DhyQPz/q69yzdIscxertlRnu0OxpCUv98d7fEVtwu5exkxOo9g=="}

[PublicKey]

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl01QaHoO+PLyZQE0/qJbxhKyHdBCVxPv+/I1i8wULdYiwhiG1OgSxyC0o8AKD9bTzVOXOd6IPb4cS8gRJUB7WlDIX+dKjQ+9BUL6yXx9gsNooJYCzKAW1/g5iRCjSaZyGzUgAPU2GxXIW3/feRRHwIkMU49Z3II37dx++Fvs6m57nbvcKJOmSOgtNvZtMq/VmDUdUTGcn1DLJiGkeaVeFsDC+kZ1hs4z9Q2Ag6yQfEYSB0gFSkC/VnQTn+ZxUtMDiIYxF44eha3hXQk5AHzn6NoebZI/Ry7vG0Gj+iRo94QcneKkiWXBY6QO0cJiVKtsqa6SaSl7u/4S8eoMzZDEvQIDAQAB

[Node.js Code]

var receipt = req.body.receipt;

iap.config({
    verbose: true,
    googlePublicKeyStrLive: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl01QaHoO+PLyZQE0/qJbxhKyHdBCVxPv+/I1i8wULdYiwhiG1OgSxyC0o8AKD9bTzVOXOd6IPb4cS8gRJUB7WlDIX+dKjQ+9BUL6yXx9gsNooJYCzKAW1/g5iRCjSaZyGzUgAPU2GxXIW3/feRRHwIkMU49Z3II37dx++Fvs6m57nbvcKJOmSOgtNvZtMq/VmDUdUTGcn1DLJiGkeaVeFsDC+kZ1hs4z9Q2Ag6yQfEYSB0gFSkC/VnQTn+ZxUtMDiIYxF44eha3hXQk5AHzn6NoebZI/Ry7vG0Gj+iRo94QcneKkiWXBY6QO0cJiVKtsqa6SaSl7u/4S8eoMzZDEvQIDAQAB",
    googlePublicKeyStrSandbox: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl01QaHoO+PLyZQE0/qJbxhKyHdBCVxPv+/I1i8wULdYiwhiG1OgSxyC0o8AKD9bTzVOXOd6IPb4cS8gRJUB7WlDIX+dKjQ+9BUL6yXx9gsNooJYCzKAW1/g5iRCjSaZyGzUgAPU2GxXIW3/feRRHwIkMU49Z3II37dx++Fvs6m57nbvcKJOmSOgtNvZtMq/VmDUdUTGcn1DLJiGkeaVeFsDC+kZ1hs4z9Q2Ag6yQfEYSB0gFSkC/VnQTn+ZxUtMDiIYxF44eha3hXQk5AHzn6NoebZI/Ry7vG0Gj+iRo94QcneKkiWXBY6QO0cJiVKtsqa6SaSl7u/4S8eoMzZDEvQIDAQAB"
});

iap.setup(function (error) {

    var convert = JSON.parse(receipt);

    iap.validate(iap.GOOGLE, convert, function (error, response) {

        if (error) {
            console.log("error = " + error);
        }

        if (iap.isValidated(response)) {

            // api
            result.status = new model.Status();
            result.status.code = 200;
            result.status.message = "SUCCESS";
            res.send(JSON.stringify(result));

            // purchaseProcess(res, purchaseUserId, purchaseType);

        } else {
            // api
            result.status = new model.Status();
            result.status.code = 500;
            result.status.message = "FAILURE";
            res.send(JSON.stringify(result));
        }

    });

});

[Output]

/usr/local/bin/node www
[1475220665152][VERBOSE] Validate this: { data:
{ packageName: 'com.skyredpepper.zzactalkandroid',
productId: 'point_1000',
purchaseTime: 1475214245609,
purchaseState: 0,
purchaseToken: 'oddidiboidodlmboahbpfgjg.AO-J1Oz4nr73R6ggq5ITwd1BYQeo7NXNTVehPsAiqeu9AuaEMaXc6OKJomOU85lbtuEGkJsFPeYlQS4Tbc9qluOvEcU1js3n6mC99FuOnpKuhCE-4BPecgSOI28_W_djaNmxIY_2zN_M' },
signature: 'fi9QIEpo NOP37L oweMiO0tcTVZiMsuu62G7ARgUPeEMO4aoZFAzGLkQzhyi A45VNvOnTcXvVuwavcpjI7tgGyDUxyKIt6Z9wub3RX1WkizKM9OimMBEZh0yGW883pYqSyDed5ZvJ9nMMeBZ47bEO0HA73h8k405e/ambf/6zUL6WNs7VeedUdcf/g9PESfIK O64MJ2AXaLifm0DE5bBFYXrT GMPX5Bv/Yi/H8eDQGBxAcNTZEo2JaLhlC6YM0DmBSOW1/f/woiXRH7mJPZNoLOJn DyZmh4DhyQPz/q69yzdIscxertlRnu0OxpCUv98d7fEVtwu5exkxOo9g==' }
[1475220665162][VERBOSE] Auto stringified receipt data: {"packageName":"com.skyredpepper.zzactalkandroid","productId":"point_1000","purchaseTime":1475214245609,"purchaseState":0,"purchaseToken":"oddidiboidodlmboahbpfgjg.AO-J1Oz4nr73R6ggq5ITwd1BYQeo7NXNTVehPsAiqeu9AuaEMaXc6OKJomOU85lbtuEGkJsFPeYlQS4Tbc9qluOvEcU1js3n6mC99FuOnpKuhCE-4BPecgSOI28_W_djaNmxIY_2zN_M"}
[1475220665163][VERBOSE] Try validate against live public key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl01QaHoO+PLyZQE0/qJbxhKyHdBCVxPv+/I1i8wULdYiwhiG1OgSxyC0o8AKD9bTzVOXOd6IPb4cS8gRJUB7WlDIX+dKjQ+9BUL6yXx9gsNooJYCzKAW1/g5iRCjSaZyGzUgAPU2GxXIW3/feRRHwIkMU49Z3II37dx++Fvs6m57nbvcKJOmSOgtNvZtMq/VmDUdUTGcn1DLJiGkeaVeFsDC+kZ1hs4z9Q2Ag6yQfEYSB0gFSkC/VnQTn+ZxUtMDiIYxF44eha3hXQk5AHzn6NoebZI/Ry7vG0Gj+iRo94QcneKkiWXBY6QO0cJiVKtsqa6SaSl7u/4S8eoMzZDEvQIDAQAB
[1475220665163][VERBOSE] Failed against live public key: [Error: failed to validate purchase]
[1475220665163][VERBOSE] Try validate against sandbox public key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl01QaHoO+PLyZQE0/qJbxhKyHdBCVxPv+/I1i8wULdYiwhiG1OgSxyC0o8AKD9bTzVOXOd6IPb4cS8gRJUB7WlDIX+dKjQ+9BUL6yXx9gsNooJYCzKAW1/g5iRCjSaZyGzUgAPU2GxXIW3/feRRHwIkMU49Z3II37dx++Fvs6m57nbvcKJOmSOgtNvZtMq/VmDUdUTGcn1DLJiGkeaVeFsDC+kZ1hs4z9Q2Ag6yQfEYSB0gFSkC/VnQTn+ZxUtMDiIYxF44eha3hXQk5AHzn6NoebZI/Ry7vG0Gj+iRo94QcneKkiWXBY6QO0cJiVKtsqa6SaSl7u/4S8eoMzZDEvQIDAQAB
[1475220665164][VERBOSE] Failed against sandbox public key: [Error: failed to validate purchase]
error = Error: failed to validate purchase


but [http://iap.gracenode.org] test output is

{
"error": null,
"response": {
"packageName": "com.skyredpepper.zzactalkandroid",
"productId": "point_1000",
"purchaseTime": 1475214245609,
"purchaseState": 0,
"purchaseToken": "oddidiboidodlmboahbpfgjg.AO-J1Oz4nr73R6ggq5ITwd1BYQeo7NXNTVehPsAiqeu9AuaEMaXc6OKJomOU85lbtuEGkJsFPeYlQS4Tbc9qluOvEcU1js3n6mC99FuOnpKuhCE-4BPecgSOI28_W_djaNmxIY_2zN_M",
"status": 0,
"service": "google"
}
}


plz help me

[ERROR] TypeError: request.defaults is not a function

Just updated to the latest version, and I'm getting this error when I start my server:

R-0 =============================== ERROR ================================
R-0 > ERR > 12:55:57:164[/usr/local/lib/node_modules/pm2/node_modules/pmx/lib/notify.js:47]
R-0         TypeError: request.defaults is not a function
R-0     at Object.module.exports.readConfig (/Users/server/Projects/app/server/node_modules/in-app-purchase/lib/apple.js:41:21)
R-0     at Object.module.exports.config (/Users/server/Projects/app/server/node_modules/in-app-purchase/index.js:15:8)
R-0     at Object.<anonymous> (/Users/server/Projects/app/server/server/controllers/iap-ctrl.js:15:5)
R-0     at Module._compile (module.js:413:34)
R-0     at Object.Module._extensions..js (module.js:422:10)
R-0     at Module.load (module.js:357:32)
R-0     at Function.Module._load (module.js:314:12)
R-0     at Function._load (/usr/local/lib/node_modules/pm2/node_modules/pmx/lib/transaction.js:62:21)
R-0     at Module.require (module.js:367:17)
R-0     at require (internal/module.js:16:19)
R-0     at Object.<anonymous> (/Users/server/Projects/app/server/server/routes/iap/verify.js:13:15)
R-0     at Module._compile (module.js:413:34)
R-0     at Object.Module._extensions..js (module.js:422:10)
R-0     at Module.load (module.js:357:32)
R-0     at Function.Module._load (module.js:314:12)
R-0     at Function._load (/usr/local/lib/node_modules/pm2/node_modules/pmx/lib/transaction.js:62:21)
R-0     at Module.require (module.js:367:17)
R-0     at require (internal/module.js:16:19)
R-0     at Object.<anonymous> (/Users/server/Projects/app/server/server/server.js:287:33)
R-0     at Module._compile (module.js:413:34)
R-0     at Object.Module._extensions..js (module.js:422:10)
R-0     at Module.load (module.js:357:32)
PM2 App [R] with id [0] and pid [700], exited with code [255] via signal [null]

My controller at

iap-ctrl.js:15:5
iap.config( {
    requestDefaults: {
        timeout: 10000
    },
    applePassword: "1337", // this comes from iTunes Connect
    googlePublicKeyStrSandbox: "1337", // this is the path to the directory containing iap-sanbox/iap-live files
    googlePublicKeyStrLive: "1337" // this is the path to the directory containing iap-sanbox/iap-live files
} )
iap.setup()

What is in googleReceipt object?

Hi Nobuyori,

I'm trying to use your module to verify IAP for android in my nodejs server.
Your module is clean and look very easy to use, I like it a lot.

But I have no idea what should be in googleReceipt object

{
    data: "{}",   <-- can you give example format of this stringified data
    signature: "" <-- this one I completely have no idea what it is, and where to get it from?
}

Can you please give more detail about googleReceipt object?

Thank you in advance.

Documentation is wrong

Please, update your documentation, you have several errors on it related to Google in app purchases configuration

In the first place, the environment variable should be GOOGLE_IAB_PUBLICKEY_SANDBOX and GOOGLE_IAB_PUBLICKEY_LIVE, NOT GOOGLE_IAB_PUBLIC_SANDBOX and GOOGLE_IAB_PUBLIC_LIVE

In the second place, the api keys as string should be called publicKeyStrSandBox and publicKeyStrLive instead of googlePublicKeyStrSandBox and googlePublicKeyStrLive

Thanks

[Proposal]: Unity receipt format

Hello @voltrue2,

Thanks for making this great project! It really saved me a lot of time in integrating receipt verification for my Unity game.

I wanted to propose a feature, which I can also implement and send a PR if you agree.

Unity has a unified IAP module which returns a specific format, which you can read about here. It is something like this:

{"Store":"GooglePlay","TransactionID":"...","Payload":"{\"json\":\"{\\\"packageName\\\":\\\"...\\\",\\\"productId\\\":\\\"...\\\",\\\"purchaseTime\\\":1479474689471,\\\"purchaseState\\\":0,\\\"purchaseToken\\\":\\\"...\\\"}\",\"signature\":\"...\"}"}

As you can see, the data already contains the store type and the receipt payload from the store. However, I don't know why, they have "json" as a key instead of "data", which makes the verification fail.

So, will it be useful if I submit a PR, something like iap.validate(iap.UNITY, unity_data, ...)? This function will automatically detect the store, and also correct the "json" key to "data" for Google Play.

Of course, if you think this is out of scope of this library, I totally understand and will implement this feature on my server code instead.

Parsed data is no longer available

It was available on 0.7.3, but not any longer.
For example, for code 21006:

{ status: 21006,
     message: 'This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response.' }

The receipt and latest_expired_receipt_info are no longer available, since in apple.js:117 and apple.js:158 validatedData is set to {status,message} losing the returned data entirely.

Apple Validation error

I am trying to validate a sandbox receipt for Apple. It works if I cURL it manually but not with your program.

Note: I have truncated the base64 string for security reasons.

//essentially the code is this:
var receipt = "ewoJInNpZ25hdHVyZSIgPSAiQTZTTDREMFFleVIyUUhk"; //this is the base64 encoded string
console.log("Input receipt: " + receipt);
iap.validate(iap.APPLE, receipt, function (err, result) {
...
Input receipt: ewoJInNpZ25hdHVyZSIgPSAiQTZTTDREMFFleVIyUUhk
Validate ERROR: Error: failed to validate purchase
verbose: error: code=141, message={"status":21002,"service":"apple","message":"The data in the receipt-data property was malformed."}

works, produces official apple output

curl --data "{\"receipt-data\":\"ewoJInNpZ25hdHVyZSIgPSAiQTZTTDREMFFleVIyUUhk\"}" https://sandbox.itunes.apple.com/verifyReceipt

Is your tool supposed to encapsulate the receipt (base64 string) into the JSON with receipt-data or am I?

Apple iAP bug

Hi,
Your library doesn't take into account of fake iap receipts. Those receipts can be generated by hacks and unfortunately it is a huge issue. Test data

Fake Receipt

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

Result from iTunes Connect (https://buy.itunes.apple.com/verifyReceipt)

{"status":0, "environment":"Production", 
"receipt":{"receipt_type":"Production", "adam_id":1015444485, "app_item_id":1015444485, "bundle_id":"com.mustafadur.Kargotakip", "application_version":"1.1.2", "download_id":28015390800003, "version_external_identifier":813135294, "receipt_creation_date":"2015-09-16 19:48:24 Etc/GMT", "receipt_creation_date_ms":"1442432904000", "receipt_creation_date_pst":"2015-09-16 12:48:24 America/Los_Angeles", "request_date":"2016-03-15 12:12:41 Etc/GMT", "request_date_ms":"1458043961971", "request_date_pst":"2016-03-15 05:12:41 America/Los_Angeles", "original_purchase_date":"2015-09-16 19:48:24 Etc/GMT", "original_purchase_date_ms":"1442432904000", "original_purchase_date_pst":"2015-09-16 12:48:24 America/Los_Angeles", "original_application_version":"1.1.2", "in_app":[]}}

As you see it has empty in_app array which fools the library. Unfortunately in this state, your library won't help to protect against piracy hacks.

I also added correct receipt and response for you so you can test it out.

Good Receipt

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

iTunes Result (https://sandbox.itunes.apple.com/verifyReceipt)

{"status":0, "environment":"Sandbox", 
"receipt":{"receipt_type":"ProductionSandbox", "adam_id":0, "app_item_id":0, "bundle_id":"com.mustafadur.Kargotakip", "application_version":"1.9.6", "download_id":0, "version_external_identifier":0, "receipt_creation_date":"2016-03-14 21:05:41 Etc/GMT", "receipt_creation_date_ms":"1457989541000", "receipt_creation_date_pst":"2016-03-14 14:05:41 America/Los_Angeles", "request_date":"2016-03-15 12:09:39 Etc/GMT", "request_date_ms":"1458043779832", "request_date_pst":"2016-03-15 05:09:39 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":[
{"quantity":"1", "product_id":"com.mustafadur.kargotakip.premium", "transaction_id":"1000000163594581", "original_transaction_id":"1000000163594581", "purchase_date":"2015-07-15 08:27:10 Etc/GMT", "purchase_date_ms":"1436948830000", "purchase_date_pst":"2015-07-15 01:27:10 America/Los_Angeles", "original_purchase_date":"2015-07-15 08:27:10 Etc/GMT", "original_purchase_date_ms":"1436948830000", "original_purchase_date_pst":"2015-07-15 01:27:10 America/Los_Angeles", "is_trial_period":"false"}]}}

Subscription Renewal?

My Android app is sending the receipt for the subscription, the receipt is being validated as real, and the expiry time is being returned, but the expiry time is for the original receipt and not renewals, so isExpired() is returning true, even though the subscription has been renewed. Am I supposed to be sending a newer receipt?

Help on Google IAB verification

Hi!

This is not very helpful as google sends a whole json object. Should I stringify google reply into "data"? I don't get what EXACTLY is expected there. A string? An object?

{"data":"google sent data","signature":"signature string"}

Here's an object from Google
{
"orderId":"12999763169054705758.1371079406387615",
"packageName":"com.example.app",
"productId":"exampleSku",
"purchaseTime":1345678900000,
"purchaseState":0,
"developerPayload":"",
"purchaseToken":"rojeslcdyyiapnqcynkjyyjh"
}

Something Seriously Wrong when using Keys in String

I am trying to use the module with Keys Passing Directly in Strings for google like

iap.config({
publicKeyStrSandBox: publicKeySandboxString,
publickKeyStrLive: publicKeyLiveString
});

But it always gives me error Missing Public Key. Please Check and Debug if you can asap as i need to use it in my project.

Validate callback is not being called with invalid receipt

  var validateReceipt = Promise.method(function() {
    inApp.config({
      applePassword: process.env.APPLE_IAP_PASSWORD
    });

    inApp.setup(function(err) {
      console.log('setup');
      if (err) {
        throw new InvalidReceiptError(err);
      }

      inApp.validate(inApp.APPLE, receipt, function(err, appleRes) {
        console.log('validate');

        if (err) {
          throw new InvalidReceiptError(err);
        }

        return appleRes;
      });
    });
  });

The call I'm doing is:

    return inApp('test_receipt')
      .validateReceipt()

but validate is never printed

incorrect spelling of "receipt" in amazon.js

Please have a look at line 81 of amazon.js. The validatePurchase function receives the parameter "receipt", but references it as "reciept" on line 81. This was mistaken caught while doing a global find on our own code for the same spelling mistake made by us elsewhere (we did the same thing!). Lucky catch.

Google receipt

In the documentation you say that the google receipt is an object with two top level key: "data" and "signature". What is the value of "data" supposed to be?

Android validate method return {}

Hi,

We have a problem when we call .validate(), in the .config we pass the keys as strings and data formatted, both are correct because we have checked it in http://iap.gracenode.org/#validate-android and the format is the same like the file test/receipts/google.

When we call to .setup() working correctly, but when call .validate() , it not enter in the function and print "{}" in mobile screen.

Do you know which is the problem?

Thanks in advance.

validationType = iap.GOOGLE;

iap.config({
verbose: true,
googlePublicKeyStrSandBox: SANDBOX_KEY_ANDROID,
googlePublicKeyStrLive: PUBLIC_KEY_ANDROID
});

datajson = { "data": JSON.parse(request[0].receipt), "signature": request[0].signature };
datastring = JSON.stringify(datajson);
data = JSON.parse(datastring);

iap.setup(function (error) {
if (error) {
console.log(error);
}
else {
iap.validate(validationType, data, function (err, response) {

      if (err) {
        console.log(err);
      }
      else {

        if (iap.isValidated(response)) {
        }
        else {
        }

      }
  });
}

});

Android validation with play store api returns error validating non subscription product

Hi, I'm probably missing something here, I'm trying to validate both type of products subscription and consumable, but when I try to validate a consumable after I validate a subscription I get an error because the plugin tries to check the subscription state and fails (obviously). I am setting a different iap.config (after setting the "config" variable inside google.js to null) before iap.setup but I still get the error.
The plugin version is 1.1.10, thanks a lot in advance.

googlePublicKeyStrSandbox Not Working (v0.5.3)

Hello,
When you set the public key directly as String, the library does not parse it well and gives the missing public key error.

My configuration is this:

  iap.config({
    applePassword: "66b24c8189d249889d454e65377d23b3",
    sandbox: true,
    googlePublicKeyStrSandBox: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtE8Y5ZYRwrHc6RJ5HGLampXt0jL3kNaZKZN2/KxloC4HuWFTFufmOjAefjogv+934Hvlmq04YQcEIh1wtqVk2WmwWvpWQK18FxBM45LksaE5S0kkzNQcWA0vjlqtZwQqlQg5ngB+xOyNojsfhGBdbLB+5s6NmSLsFfzgW29/tLxPHfewzEgFLmJ4PSRZo9ObPnLowYlZ7yDEaS6AIu739OnAwdU9qVWOo++TBLoLJ6+bT5fPMMSteZFfaEp+3QBM+qdNnnJ8zYMVHIYnD77GLBT08xLUiO8FnSEZZC5GAmYFmiJN8NKGMnt+bxy6+hhdcGatoUnMzzmSHvTjV3j1XQIDAQAB"
  });

When debugging the library I found this:

At in-app-purchase/lib/google.js, at configuration in line 59,

It can be seen that it is not entering in this if:

if (config && (config.googlePublicKeyStrSandbox || config.googlePublicKeyStrLive)) {

At that moment the value of config variable is:

{ googlePublicKeyStrSandBox: 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtE8Y5ZYRwrHc6RJ5HGLampXt0jL3kNaZKZN2/KxloC4HuWFTFufmOjAefjogv+934Hvlmq04YQcEIh1wtqVk2WmwWvpWQK18FxBM45LksaE5S0kkzNQcWA0vjlqtZwQqlQg5ngB+xOyNojsfhGBdbLB+5s6NmSLsFfzgW29/tLxPHfewzEgFLmJ4PSRZo9ObPnLowYlZ7yDEaS6AIu739OnAwdU9qVWOo++TBLoLJ6+bT5fPMMSteZFfaEp+3QBM+qdNnnJ8zYMVHIYnD77GLBT08xLUiO8FnSEZZC5GAmYFmiJN8NKGMnt+bxy6+hhdcGatoUnMzzmSHvTjV3j1XQIDAQAB' }

So definitely it has been read but somehow config.googlePublicKeyStrSandbox outputs undefined

Cancellation flag is not checked for Apple Receipts

If a subscription is cancelled by the user or if the payment process fails a cancellation date is added to the receipt by the apple server. This flag is currently not checked by your implementation. So the module will return false when calling isExpired() even though the receipt was cancelled and is no longer valid.

Google product validation support

Hi,

At the moment I see that only subscriptions are able to be validated. According to https://developers.google.com/android-publisher/api-ref/purchases/products/get the products use other url. However, I was able to validate successfully a payment with the library by only changing the url in the checkSubscriptionStatus method (replacing /purchases/subscriptions/ with /purchases/products/)

I think a simple way to be able to add support on this, is to add a parameter in the receipt object that is passed through the validate method, something to be able to distinguish between a subscription and a purchase. After changing the url would be enought.

Do you think it is feasible to implement such a small feature ?

LICENSE Policy

I'm a bit confused as to what your license policy states.

I'm familiar with the MIT, but that's about it. Am I able to use this project in a commercial product I'm selling to verify my in app purchases?

CERT_UNTRUSTED occurs for apple validate requests

The send function in apple.js returns the error "CERT_UNTRUSTED" to the validatePurchase callback, and the check for data.status results in the process terminating, as data is null in this case.

If send is modified to the following ("rejectUnauthorized : false" added), everything works fine.

function send(url, content, cb) {
var options = {
encoding: null,
url: url,
body: content,
json: true,
rejectUnauthorized : false
};
request.post(options, function (error, res, body) {
return cb(error, res, body);
});
}

Same version different code ?

Hi, about four months ago I installed your library and saved it to my project package.json as "in-app-purchase": "0.3.0"
A few days ago I ran npm install on the same package.json, but the downloaded code looked different from the one I have on my laptop where I developed my application.
For example i see some differences in in-app-purchase/lib/apple.js.
I'm quite puzzled with this situation I'd just like to be able to download via npm the same version I used during development.
Here some lines of code, for me different in lib/apple.js

function isValidConfigKey(key) {
return key.match(/^apple/);
}

module.exports.setup = function (cb) {
if (!config || !config.applePassword) {

    if (process.env.APPLE_IAP_PASSWORD) {
        config = config || {};
        config.applePassword = process.env.APPLE_IAP_PASSWORD;
    }

}

return cb();

};

etc, etc

I hope we will sort this out,
thanks for your work.
Claudio Forgiarini
[email protected]

Error in amazon.js when trying to validate apple receipt

Hi,

I've just installed v0.5.0 and I get the following error when trying to validate an apple receipt:

"error": [
    "TypeError: Cannot read property 'secret' of undefined",
    "at Object.module.exports.setup (.../node_modules/in-app-purchase/lib/amazon.js:43:18)",
    ...

my code:

iap.setup(function (err) {
        if (err) {
          console.log(err);
        }
        iap.validate(iap.APPLE, context.receipt, function (err, response) {
          if (err) {
            console.log(err);
          }
          console.log('response', response);
          if (iap.isValidated(response)) {
            console.log(iap.getPurchaseData(response));
          }
        });
      });

validateOnce

Hi!

Exciting update this one. So the second param is either iTunes secret or any of my app's Google Play private keys?

IAP.getPurchaseData ignoring latest purchase

Hey Guys

Thanks for this great module.

My app implements Apple autorenewable subscriptions. But now some of the subscriptions have renewed (the initial subscription being a monthly subscription just over a month ago) the IAP node module isn't recognising this and treats repeat subscriptions as expired.

I can see the reason for the bug in the source code too:

https://github.com/voltrue2/in-app-purchase/blob/develop/lib/apple.js#L190

REC_KEYS.IN_APP references the array named 'in_app' but for some reason Apple's auto-renewable receipts only include the new purchases within an array named 'latest_receipt_info'.

Here's an example:

in_app: 
      [ { quantity: '1',
          product_id: 'blah.blah.blah',
          transaction_id: '210000259386802',
          original_transaction_id: '210000259386802',
          purchase_date: '2016-04-14 16:03:33 Etc/GMT',
          purchase_date_ms: '1460649813000',
          purchase_date_pst: '2016-04-14 09:03:33 America/Los_Angeles',
          original_purchase_date: '2016-04-14 16:03:34 Etc/GMT',
          original_purchase_date_ms: '1460649814000',
          original_purchase_date_pst: '2016-04-14 09:03:34 America/Los_Angeles',
          expires_date: '2016-05-14 16:03:33 Etc/GMT',
          expires_date_ms: '1463241813000',
          expires_date_pst: '2016-05-14 09:03:33 America/Los_Angeles',
          web_order_line_item_id: '210000038560504',
          is_trial_period: 'false' } ] },
  latest_receipt_info: 
   [ { quantity: '1',
       product_id: 'blah.blah.blah',
       transaction_id: '210000259386802',
       original_transaction_id: '210000259386802',
       purchase_date: '2016-04-14 16:03:33 Etc/GMT',
       purchase_date_ms: '1460649813982',
       purchase_date_pst: '2016-04-14 09:03:33 America/Los_Angeles',
       original_purchase_date: '2016-04-14 16:03:34 Etc/GMT',
       original_purchase_date_ms: '1460649814000',
       original_purchase_date_pst: '2016-04-14 09:03:34 America/Los_Angeles',
       expires_date: '2016-05-14 16:03:33 Etc/GMT',
       expires_date_ms: '1463241813982',
       expires_date_pst: '2016-05-14 09:03:33 America/Los_Angeles',
       web_order_line_item_id: '210000038560504',
       is_trial_period: 'false' },
     { quantity: '1',
       product_id: 'blah.blah.blah',
       transaction_id: '210000265773203',
       original_transaction_id: '210000259386802',
       purchase_date: '2016-05-14 16:03:33 Etc/GMT',
       purchase_date_ms: '1463241813000',
       purchase_date_pst: '2016-05-14 09:03:33 America/Los_Angeles',
       original_purchase_date: '2016-05-14 10:03:37 Etc/GMT',
       original_purchase_date_ms: '1463220217552',
       original_purchase_date_pst: '2016-05-14 03:03:37 America/Los_Angeles',
       expires_date: '2016-06-14 16:03:33 Etc/GMT',
       expires_date_ms: '1465920213000',
       expires_date_pst: '2016-06-14 09:03:33 America/Los_Angeles',
       web_order_line_item_id: '210000038560503',
       is_trial_period: 'false' } ],

As you can see above this customer's second subscription payment completed for another month's use of my app. However, calling

IAP.getPurchaseData(appleRes);

Results in parsing the 'in_app' array and not the 'latest_receipt_info' array that contains the latest purchase.

Is this a change in Apple's receipt format?

Cheers

Nick

validate returns an error

I am trying to use your module and have copied in the sample code you've given:

    iap.setup(function (error) {
        if (error) {
            // error hmm 
        }
        iap.validate(iap.APPLE, function (error, response) {
            if (error) {
                // error 
            }
            if (iap.isValidated(response)) {
                var purcahseDataList = iap.getPurchaseData(response);
                /*
                    [
                        {
                            productId: xxx,
                            purchasedDate: yyy,
                            quantity: zzz
                        }
                    ]
                */
            }
        });
    });

However I'm getting the error about validate?

[ERROR] TypeError: undefined is not a function
    at /Users/gurmukh.panesar/Sites/iap/node_modules/in-app-purchase/index.js:45:11
    at handleResponse (/Users/gurmukh.panesar/Sites/iap/node_modules/in-app-purchase/lib/apple.js:115:2)
    at /Users/gurmukh.panesar/Sites/iap/node_modules/in-app-purchase/lib/apple.js:78:3
    at Request._callback (/Users/gurmukh.panesar/Sites/iap/node_modules/in-app-purchase/lib/apple.js:129:10)
    at Request.self.callback (/Users/gurmukh.panesar/Sites/iap/node_modules/in-app-purchase/node_modules/request/request.js:122:22)
    at Request.EventEmitter.emit (events.js:98:17)
    at Request.<anonymous> (/Users/gurmukh.panesar/Sites/iap/node_modules/in-app-purchase/node_modules/request/request.js:888:14)
    at Request.EventEmitter.emit (events.js:117:20)
    at IncomingMessage.<anonymous> (/Users/gurmukh.panesar/Sites/iap/node_modules/in-app-purchase/node_modules/request/request.js:839:12)
    at IncomingMessage.EventEmitter.emit (events.js:117:20)

I'm using Express 3.0, if that's any help

Occassional error transactionId of undefined

Check this response

[IAP] validated response { status: 0,
2016-04-01T15:15:23.271Z pid:21966 worker:3 environment: 'Production',
2016-04-01T15:15:23.272Z pid:21966 worker:3 receipt:
2016-04-01T15:15:23.272Z pid:21966 worker:3 { receipt_type: 'Production',
2016-04-01T15:15:23.272Z pid:21966 worker:3 adam_id: XXXXX,
2016-04-01T15:15:23.272Z pid:21966 worker:3 app_item_id: XXX,
2016-04-01T15:15:23.272Z pid:21966 worker:3 bundle_id: 'xxxx',
2016-04-01T15:15:23.272Z pid:21966 worker:3 application_version: '2.1.7',
2016-04-01T15:15:23.272Z pid:21966 worker:3 download_id: 1234,
2016-04-01T15:15:23.273Z pid:21966 worker:3 version_external_identifier: 1234,
2016-04-01T15:15:23.273Z pid:21966 worker:3 receipt_creation_date: '2016-04-01 15:01:22 Etc/GMT',
2016-04-01T15:15:23.273Z pid:21966 worker:3 receipt_creation_date_ms: '1459522882000',
2016-04-01T15:15:23.273Z pid:21966 worker:3 receipt_creation_date_pst: '2016-04-01 08:01:22 America/Los_Angeles',
2016-04-01T15:15:23.273Z pid:21966 worker:3 request_date: '2016-04-01 15:15:23 Etc/GMT',
2016-04-01T15:15:23.273Z pid:21966 worker:3 request_date_ms: '1459523723225',
2016-04-01T15:15:23.273Z pid:21966 worker:3 request_date_pst: '2016-04-01 08:15:23 America/Los_Angeles',
2016-04-01T15:15:23.273Z pid:21966 worker:3 original_purchase_date: '2016-04-01 15:01:22 Etc/GMT',
2016-04-01T15:15:23.273Z pid:21966 worker:3 original_purchase_date_ms: '1459522882000',
2016-04-01T15:15:23.274Z pid:21966 worker:3 original_purchase_date_pst: '2016-04-01 08:01:22 America/Los_Angeles',
2016-04-01T15:15:23.274Z pid:21966 worker:3 original_application_version: '2.1.7',
2016-04-01T15:15:23.274Z pid:21966 worker:3 in_app: [] },
2016-04-01T15:15:23.274Z pid:21966 worker:3 service: 'apple' } []
2016-04-01T15:15:23.274Z pid:21966 worker:3 uncaught Exception { [TypeError: Cannot read property 'transactionId' of undefined]
2016-04-01T15:15:23.274Z pid:21966 worker:3 domain:
2016-04-01T15:15:23.274Z pid:21966 worker:3 { domain: null,
2016-04-01T15:15:23.274Z pid:21966 worker:3 _events: {},
2016-04-01T15:15:23.275Z pid:21966 worker:3 _maxListeners: 10,
2016-04-01T15:15:23.275Z pid:21966 worker:3 members: [ [Object], [Object] ],
2016-04-01T15:15:23.275Z pid:21966 worker:3 oldBind: [Function],
2016-04-01T15:15:23.275Z pid:21966 worker:3 bind: [Function] },
2016-04-01T15:15:23.275Z pid:21966 worker:3 domainThrown: true }

Multiple Products Expire Validation

Hi All,

I'm trying to use this plugin in order to validate ios IAP, but i've one question that has really no sense to me...

When a recepit is received it can have multiple products and how can i send a response for specific product expire (even if others are not) if the request contains all the products?

I'm using the ordova-plugin-purchase for managing auto-renew subscription and this issue is blocking me.

if (iap.isValidated(response)) {
// now check if any of the items validated has been expired or not
var purchaseDataList = iap.getPurchaseData(response);
for (var i = 0, len = purchaseDataList.length; i < len; i++) {
if (iap.isExpired(purchaseDataList[i])) {
// this item has been expired...
}
}
}

In the example in the documentation is explained that a cycle is used for checking the expiration of a product and I was thinking to return an expiring status if i found one expired... but in this way my response will be just one for all the products stopping the cycle even if not all are expired or valid.

Many Thanks,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.