Now handles top level files and recursive files in folders. Set max line length to be 100
124 lines
3.8 KiB
JavaScript
124 lines
3.8 KiB
JavaScript
import PromiseRouter from '../PromiseRouter';
|
|
const request = require('../request');
|
|
const rest = require('../rest');
|
|
import Parse from 'parse/node';
|
|
|
|
// TODO move validation logic in IAPValidationController
|
|
const IAP_SANDBOX_URL = 'https://sandbox.itunes.apple.com/verifyReceipt';
|
|
const IAP_PRODUCTION_URL = 'https://buy.itunes.apple.com/verifyReceipt';
|
|
|
|
const APP_STORE_ERRORS = {
|
|
21000: 'The App Store could not read the JSON object you provided.',
|
|
21002: 'The data in the receipt-data property was malformed or missing.',
|
|
21003: 'The receipt could not be authenticated.',
|
|
21004: 'The shared secret you provided does not match the shared secret on file for your account.',
|
|
21005: 'The receipt server is not currently available.',
|
|
21006: 'This receipt is valid but the subscription has expired.',
|
|
21007: 'This receipt is from the test environment, but it was sent to the production environment for verification. Send it to the test environment instead.',
|
|
21008: 'This receipt is from the production environment, but it was sent to the test environment for verification. Send it to the production environment instead.',
|
|
};
|
|
|
|
function appStoreError(status) {
|
|
status = parseInt(status);
|
|
var errorString = APP_STORE_ERRORS[status] || 'unknown error.';
|
|
return { status: status, error: errorString };
|
|
}
|
|
|
|
function validateWithAppStore(url, receipt) {
|
|
return request({
|
|
url: url,
|
|
method: 'POST',
|
|
body: { 'receipt-data': receipt },
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
}).then(httpResponse => {
|
|
const body = httpResponse.data;
|
|
if (body && body.status === 0) {
|
|
// No need to pass anything, status is OK
|
|
return;
|
|
}
|
|
// receipt is from test and should go to test
|
|
throw body;
|
|
});
|
|
}
|
|
|
|
function getFileForProductIdentifier(productIdentifier, req) {
|
|
return rest
|
|
.find(
|
|
req.config,
|
|
req.auth,
|
|
'_Product',
|
|
{ productIdentifier: productIdentifier },
|
|
undefined,
|
|
req.info.clientSDK,
|
|
req.info.context
|
|
)
|
|
.then(function (result) {
|
|
const products = result.results;
|
|
if (!products || products.length != 1) {
|
|
// Error not found or too many
|
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
|
|
}
|
|
|
|
var download = products[0].download;
|
|
return Promise.resolve({ response: download });
|
|
});
|
|
}
|
|
|
|
export class IAPValidationRouter extends PromiseRouter {
|
|
handleRequest(req) {
|
|
let receipt = req.body.receipt;
|
|
const productIdentifier = req.body.productIdentifier;
|
|
|
|
if (!receipt || !productIdentifier) {
|
|
// TODO: Error, malformed request
|
|
throw new Parse.Error(Parse.Error.INVALID_JSON, 'missing receipt or productIdentifier');
|
|
}
|
|
|
|
// Transform the object if there
|
|
// otherwise assume it's in Base64 already
|
|
if (typeof receipt == 'object') {
|
|
if (receipt['__type'] == 'Bytes') {
|
|
receipt = receipt.base64;
|
|
}
|
|
}
|
|
|
|
if (process.env.TESTING == '1' && req.body.bypassAppStoreValidation) {
|
|
return getFileForProductIdentifier(productIdentifier, req);
|
|
}
|
|
|
|
function successCallback() {
|
|
return getFileForProductIdentifier(productIdentifier, req);
|
|
}
|
|
|
|
function errorCallback(error) {
|
|
return Promise.resolve({ response: appStoreError(error.status) });
|
|
}
|
|
|
|
return validateWithAppStore(IAP_PRODUCTION_URL, receipt).then(
|
|
() => {
|
|
return successCallback();
|
|
},
|
|
error => {
|
|
if (error.status == 21007) {
|
|
return validateWithAppStore(IAP_SANDBOX_URL, receipt).then(
|
|
() => {
|
|
return successCallback();
|
|
},
|
|
error => {
|
|
return errorCallback(error);
|
|
}
|
|
);
|
|
}
|
|
|
|
return errorCallback(error);
|
|
}
|
|
);
|
|
}
|
|
|
|
mountRoutes() {
|
|
this.route('POST', '/validate_purchase', this.handleRequest);
|
|
}
|
|
}
|