1

I'm attempting to verify the integrity of a consumable purchase in my app.

I've tested my in app purchase and it works fine. However, upon testing it with an "In-App-Purchase Cracker" with a jailbroken device, I realized that All of my receipts returned ok by apple's servers regardless of whether the purchase actually happened or not.

My transaction listener:

-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions)
{
    switch (transaction.transactionState) {
        case SKPaymentTransactionStatePurchased:
            [self unlockFeature];
            [[SKPaymentQueue defaultQueue]
             finishTransaction:transaction];
            break;

        case SKPaymentTransactionStateFailed:
            NSLog(@"Transaction Failed");
            [[SKPaymentQueue defaultQueue]
             finishTransaction:transaction];
            break;

        default:
            break;
    }
}

unlockFeature:

 NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
NSString *rs = [receipt base64EncodedStringWithOptions:kNilOptions];
NSInteger amt = _cDonAmt;
_cDonAmt = 0;
if (receipt) {
NSURL *url = [NSURL URLWithString:@"http://example.com/verifyDonation.php"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:[MasterViewController getUserId] forKey:@"userID"];
    [request setPostValue:rs forKey:@"receipt"];
    [request setPostValue:[NSString stringWithFormat:@"%ld",(long)amt] forKey:@"dAmt"];
[request setDelegate:self];
[request startAsynchronous];
}

I'm hoping that my error might lie in my PHP Verification script

<?php

class VerifyDonation {


function verify() {
    $uid = htmlspecialchars($_POST["userID"]);
    $dA = intval(htmlspecialchars($_POST["dAmt"]));
    $receipti = $_POST["receipt"];
    $sandbox = true;
   //start getting
      if ($sandbox)
    $verify_host = "ssl://sandbox.itunes.apple.com";
else
    $verify_host = "ssl://buy.itunes.apple.com";

$json='{"receipt-data" : "'.$receipti.'" }';
//opening socket to itunes
$fp = fsockopen ($verify_host, 443, $errno, $errstr, 30);
if (!$fp) 
{
    // HTTP ERROR
    return false;
} 
else
{ 
    //iTune's request url is /verifyReceipt     
    $header = "POST /verifyReceipt HTTP/1.0\r\n";
    $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
    $header .= "Content-Length: " . strlen($json) . "\r\n\r\n";
    fputs ($fp, $header . $json);
    $res = '';
    while (!feof($fp)) 
    {
        $step_res = fgets ($fp, 1024);
        $res = $res . $step_res;
    }
    fclose ($fp);
    //taking the JSON response
    $json_source = substr($res, stripos($res, "\r\n\r\n{") + 4);
    //decoding
    $app_store_response_map = json_decode($json_source);
    $app_store_response_status = $app_store_response_map->{'status'};
    //end geting
    if ($app_store_response_status == 0)//eithr OK or expired and needs to synch
    {
        echo "validReceipt";


         $link = mysql_connect("localhost", "user", "pass") or
        die("Could not connect: " . mysql_error());
    mysql_select_db("database");
    mysql_query("UPDATE `users` SET `donarAmt`= donarAmt + $dA WHERE facebookId = $uid");
        return true;
    }
    else
    {
        echo "invalidReceipt";
        return false;
    }
}

}
}


// This is the first thing that gets called when this page is loaded
// Creates a new instance of the RedeemAPI class and calls the redeem method
$ver = new VerifyDonation;
$ver->verify();

?>
  • 1
    Please, [don't use `mysql_*` functions](http://stackoverflow.com/questions/12859942/why-shouldnt-i-use-mysql-functions-in-php). They are no longer maintained and are [officially deprecated](https://wiki.php.net/rfc/mysql_deprecation). Learn about [prepared statements](http://en.wikipedia.org/wiki/Prepared_statement) instead, and use [PDO](http://us1.php.net/pdo) or [MySQLi](http://us1.php.net/mysqli). – Jay Blanchard Jan 12 '15 at 19:24
  • 2
    @JayBlanchard The problem here is not the MySQL. It works as I need it to when $app_store_response_status is 0... Which it always is for some reason – Nicholas Conrad Jan 12 '15 at 19:34
  • @NicholasConrad have you checked the full dump `var_dump($app_store_response_map)` – meda Jan 12 '15 at 19:34
  • Regardless of the issue @NicholasConrad, the MySQL functions as written will become a problem. – Jay Blanchard Jan 12 '15 at 19:40

0 Answers0