diff --git a/config.json.example b/config.json.example index d8bb67b62e..caedcf3ae9 100644 --- a/config.json.example +++ b/config.json.example @@ -41,5 +41,6 @@ "mode":"sandbox", "client_id":"client_id", "client_secret":"client_secret" - } + }, + "IAP_GOOGLE_KEYDIR": "/path/to/google/public/key/dir/" } diff --git a/package.json b/package.json index fc3edb043b..061d4a227e 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "grunt-nodemon": "~0.3.0", "habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared#develop", "icalendar": "git://github.com/lefnire/node-icalendar#master", + "in-app-purchase": "^0.2.0", "jade": "~1.7.0", "js2xmlparser": "~0.1.2", "lodash": "~2.4.1", diff --git a/src/controllers/payments/iap.js b/src/controllers/payments/iap.js new file mode 100644 index 0000000000..29b03fedfb --- /dev/null +++ b/src/controllers/payments/iap.js @@ -0,0 +1,129 @@ +var iap = require('in-app-purchase'); +var async = require('async'); +var payments = require('./index'); +var nconf = require('nconf'); + +var inAppPurchase = require('in-app-purchase'); +inAppPurchase.config({ + // this is the path to the directory containing iap-sanbox/iap-live files + googlePublicKeyPath: nconf.get("IAP_GOOGLE_KEYDIR") +}); + +// Validation ERROR Codes +var INVALID_PAYLOAD = 6778001; +var CONNECTION_FAILED = 6778002; +var PURCHASE_EXPIRED = 6778003; + +exports.androidVerify = function(req, res, next) { + var iapBody = req.body; + var user = res.locals.user; + + iap.setup(function (error) { + if (error) { + var resObj = { + ok: false, + data: 'IAP Error' + }; + + console.error('IAP Setup ERROR'); + console.error(error); + + res.json(resObj); + + return; + } + + /* + google receipt must be provided as an object + { + "data": "{stringified data object}", + "signature": "signature from google" + } + */ + var testObj = { + data: iapBody.transaction.receipt, + signature: iapBody.transaction.signature + }; + + // iap is ready + iap.validate(iap.GOOGLE, testObj, function (err, googleRes) { + if (err) { + var resObj = { + ok: false, + data: { + code: INVALID_PAYLOAD, + message: err.toString() + } + }; + + res.json(resObj); + console.error(err); + return; + } + + if (iap.isValidated(googleRes)) { + var resObj = { + ok: true, + data: googleRes + }; + + payments.buyGems({user:user, paymentMethod:'IAP GooglePlay'}); + + // yay good! + res.json(resObj); + } + }); + }); +}; + +exports.iosVerify = function(req, res, next) { + console.info(req.body); + + var iapBody = req.body; + var user = res.locals.user; + + iap.setup(function (error) { + if (error) { + var resObj = { + ok: false, + data: 'IAP Error' + }; + + console.error('IAP Setup ERROR'); + console.error(error); + + res.json(resObj); + + return; + } + + // iap is ready + iap.validate(iap.APPLE, iapBody.transaction.receipt, function (err, appleRes) { + if (err) { + var resObj = { + ok: false, + data: { + code: INVALID_PAYLOAD, + message: err.toString() + } + }; + + res.json(resObj); + console.error(err); + return; + } + + if (iap.isValidated(appleRes)) { + var resObj = { + ok: true, + data: appleRes + }; + + payments.buyGems({user:user, paymentMethod:'IAP AppleStore'}); + + // yay good! + res.json(resObj); + } + }); + }); +}; \ No newline at end of file diff --git a/src/controllers/payments/index.js b/src/controllers/payments/index.js index 176098b4c5..b0c59f643c 100644 --- a/src/controllers/payments/index.js +++ b/src/controllers/payments/index.js @@ -7,9 +7,9 @@ var moment = require('moment'); var isProduction = nconf.get("NODE_ENV") === "production"; var stripe = require('./stripe'); var paypal = require('./paypal'); -var User = require('mongoose').model('User'); var members = require('../members') var async = require('async'); +var iap = require('./iap'); function revealMysteryItems(user) { _.each(shared.content.gear.flat, function(item) { @@ -123,4 +123,7 @@ exports.paypalSubscribeSuccess = paypal.executeBillingAgreement; exports.paypalSubscribeCancel = paypal.cancelSubscription; exports.paypalCheckout = paypal.createPayment; exports.paypalCheckoutSuccess = paypal.executePayment; -exports.paypalIPN = paypal.ipn; \ No newline at end of file +exports.paypalIPN = paypal.ipn; + +exports.iapAndroidVerify = iap.androidVerify; +exports.iapIosVerify = iap.iosVerify; diff --git a/src/routes/payments.js b/src/routes/payments.js index c34d77b24b..adc9a65629 100644 --- a/src/routes/payments.js +++ b/src/routes/payments.js @@ -17,4 +17,7 @@ router.post("/stripe/subscribe/edit", auth.auth, i18n.getUserLanguage, payments. //router.get("/stripe/subscribe", auth.authWithUrl, i18n.getUserLanguage, payments.stripeSubscribe); // checkout route is used (above) with ?plan= instead router.get("/stripe/subscribe/cancel", auth.authWithUrl, i18n.getUserLanguage, payments.stripeSubscribeCancel); +router.post("/iap/android/verify", auth.authWithUrl, /*i18n.getUserLanguage, */payments.iapAndroidVerify); +router.post("/iap/ios/verify", /*auth.authWithUrl, i18n.getUserLanguage, */ payments.iapIosVerify); + module.exports = router; \ No newline at end of file