diff --git a/README.md b/README.md index de3fe4e..c0e65e0 100644 --- a/README.md +++ b/README.md @@ -110,14 +110,26 @@ MIT ### Google Play References +**Code Inspiration** + * https://bitbucket.org/gooroo175/google-play-purchase-validator/src/d88278c30df0d0dc51b852b7bcab5f40e3a30923/index.js?at=master * https://github.com/machadogj/node-google-bigquery * https://github.com/extrabacon/google-oauth-jwt/blob/master/lib/request-jwt.js + +**API Reference** * https://developer.android.com/google/play/billing/gp-purchase-status-api.html + * https://developers.google.com/android-publisher/ * https://developers.google.com/android-publisher/getting_started * https://developers.google.com/android-publisher/authorization * https://developers.google.com/accounts/docs/OAuth2ServiceAccount * https://developers.google.com/android-publisher/api-ref/purchases/products * https://developers.google.com/android-publisher/api-ref/purchases/products/get - * http://developer.android.com/google/play/billing/billing_testing.html \ No newline at end of file + * http://developer.android.com/google/play/billing/billing_testing.html + * http://stackoverflow.com/questions/24323207/use-service-account-to-verify-google-inapppurchase + +**Receipt Generation** + + * http://developer.android.com/training/in-app-billing/preparing-iab-app.html + * http://developer.android.com/tools/publishing/app-signing.html + * http://developer.android.com/google/play/billing/api.html#managed \ No newline at end of file diff --git a/lib/apple/index.js b/lib/apple/index.js index a44e6e4..19b0977 100644 --- a/lib/apple/index.js +++ b/lib/apple/index.js @@ -43,11 +43,15 @@ function parseResult(result) { function verify(environmentUrl, options, cb) { - https.post(environmentUrl, options, function (error, resultString) { + https.post(environmentUrl, options, function (error, res, resultString) { if (error) { return cb(error); } + if (res.statusCode !== 200) { + return cb(new Error('Received ' + res.statusCode + ' status code with body: ' + responseData)); + } + var resultObject; try { diff --git a/lib/google/index.js b/lib/google/index.js index 2c3ebf0..dea7288 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -32,13 +32,29 @@ exports.verifyPayment = function (payment, cb) { requestToken.access_token ); - https.get(requestUrl, null, function (error, responseString) { + https.get(requestUrl, null, function (error, res, responseString) { if (error) { return cb(error); } - console.log('\nResult:', responseString); - return cb(); + if (res.statusCode !== 200) { + return cb(new Error('Received ' + res.statusCode + ' status code with body: ' + responseData)); + } + + var responseObject; + try { + responseObject = JSON.parse(responseString); + assert.equal(responseObject.purchaseState, 0, 'purchaseCancelled'); + assert.equal(responseObject.consumptionState, 1, 'notConsumed'); + } catch (e) { + return cb(e); + } + + return cb(null, { + receipt: responseObject, + transactionId: payment.receipt, + productId: payment.productId, + }); }); }); }; \ No newline at end of file diff --git a/lib/google/jwt.js b/lib/google/jwt.js index d2fd94a..55b13a9 100644 --- a/lib/google/jwt.js +++ b/lib/google/jwt.js @@ -20,11 +20,15 @@ exports.getToken = function (iss, key, scope, cb) { assertion: jwtToken } - https.post(apiUrls.tokenRequest, { form: formData }, function (error, responseString) { + https.post(apiUrls.tokenRequest, { form: formData }, function (error, res, responseString) { if (error) { return cb(error); } + if (res.statusCode !== 200) { + return cb(new Error('Received ' + res.statusCode + ' status code with body: ' + responseData)); + } + var responseObject; try { responseObject = JSON.parse(responseString); diff --git a/lib/google/urls.js b/lib/google/urls.js index 03c701f..0fbe9a3 100644 --- a/lib/google/urls.js +++ b/lib/google/urls.js @@ -11,13 +11,12 @@ exports.publisherScope = 'https://www.googleapis.com/auth/androidpublisher'; // Android Purchases URLs & generators exports.purchasesProductsGet = function (packageName, productId, receipt, accessToken) { - var baseUrl = 'https://www.googleapis.com/androidpublisher/v2'; - var packageUri = 'applications/' + encodeURIComponent(packageName); - var productUri = 'purchases/products/' + encodeURIComponent(productId); - var receiptUri = 'tokens/' + encodeURIComponent(receipt); + var urlFormat = 'https://www.googleapis.com/androidpublisher/v2/applications/%s/purchases/products/%s/tokens/%s?access_token=%s'; - var purchaseUrl = [baseUrl, packageUri, productUri, receiptUri].join('/'); - var accessToken = 'access_token=' + encodeURIComponent(accessToken); - - return purchaseUrl + '?' + accessToken; + return util.format(urlFormat, + encodeURIComponent(packageName), // application package name + encodeURIComponent(productId), // productId + encodeURIComponent(receipt), // purchase token + encodeURIComponent(accessToken) // API access token + ); }; \ No newline at end of file diff --git a/lib/https/post.js b/lib/https/post.js index c7b6296..2cc13ba 100644 --- a/lib/https/post.js +++ b/lib/https/post.js @@ -10,14 +10,12 @@ module.exports = function (url, options, cb) { try { if (options.form) { data = formUrlencoded.encode(options.form); - delete options.form; options.headers = { 'content-type': 'application/x-www-form-urlencoded', 'content-length': Buffer.byteLength(data) }; } else if (data.json) { data = JSON.stringify(data.json); - delete options.json; options.headers = { 'content-type': 'application/json', 'content-length': Buffer.byteLength(data) diff --git a/lib/https/request.js b/lib/https/request.js index 45956f4..f71dbde 100644 --- a/lib/https/request.js +++ b/lib/https/request.js @@ -29,11 +29,7 @@ module.exports = function (requestUrl, options, data, cb) { }); res.on('end', function () { - if (res.statusCode !== 200) { - return cb(new Error('Received ' + res.statusCode + ' status code with body: ' + responseData)); - } - - cb(null, responseData); + cb(null, res, responseData); }); });