Validate your INAPP purchase with APPLE server

InApp purchase validation IOS

Fraud, happened to so many app developers where in-app purchase never occurs with server and request was redirected to dummy server so that user can unlock in-app for free. Mostly happened in jailbroken devices that let app developer frustrated as in-app is the way to get some bucks in his/her pocket as app revenue.

                                    There is no way to correct this apart from implementing a server validation of the receipt that is returned after successful in-app purchase. If you tried to do validation within the app then you will never broke this fraud as hackers can change DNS server settings within your devices. In this post i am going to post code that let you verify your in-app purchase with in the app.

We will call below given method, getStoreReceipt in method

– (void) completedPurchaseTransaction: (SKPaymentTransaction *) transaction

getStoreReceipt takes a bool to determine wether you are testing in-app against a SANDBOX environment or LIVE server. Below is the code , you can copy paste whole code and paste into the class where you implemented completedPurchaseTransaction method.
Method 1: 
// this returns an NSDictionary of the app’s store receipt, status=0 for good, -1 for bad
– (NSDictionary *)getStoreReceipt:(BOOL)sandbox {
    
    NSArray *objects;
    NSArray *keys;
    NSDictionary *dictionary;
    
    BOOL gotreceipt = false;
    
    @try {
        
        NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];
        
        if ([[NSFileManager defaultManager] fileExistsAtPath:[receiptUrl path]]) {
            
            NSData *receiptData = [NSData dataWithContentsOfURL:receiptUrl];
            
            NSString *receiptString = [self base64forData:receiptData];
            
            if (receiptString != nil) {
                
                objects = [[NSArray alloc] initWithObjects:receiptString, nil];
                keys = [[NSArray alloc] initWithObjects:@”receipt-data”, nil];
                dictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
                
               NSData *postData1  = [NSJSONSerialization dataWithJSONObject:dictionary options:NSJSONWritingPrettyPrinted error:nil];
                NSString *postData =[[NSString alloc] initWithData:postData1 encoding:NSUTF8StringEncoding];
                NSString *urlSting = @”https://buy.itunes.apple.com/verifyReceipt”;
                if (sandbox) urlSting = @”https://sandbox.itunes.apple.com/verifyReceipt”;
                
                dictionary = [self getJsonDictionaryWithPostFromUrlString:urlSting andDataString:postData];
                
                if ([dictionary objectForKey:@”status”] != nil) {
                    
                    if ([[dictionary objectForKey:@”status”] intValue] == 0) {
                        
                        gotreceipt = true;
                        
                    }
                }
                
            }
            
        }
        
    } @catch (NSException * e) {
        gotreceipt = false;
    }
    
    if (!gotreceipt) {
        objects = [[NSArray alloc] initWithObjects:@”-1″, nil];
        keys = [[NSArray alloc] initWithObjects:@”status”, nil];
        dictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
    }
    
    return dictionary;
}
Method 2: 
– (NSDictionary *) getJsonDictionaryWithPostFromUrlString:(NSString *)urlString andDataString:(NSString *)dataString {
    NSString *jsonString = [self getStringWithPostFromUrlString:urlString andDataString:dataString];
    NSLog(@”%@”, jsonString); // see what the response looks like
    return [self getDictionaryFromJsonString:jsonString];
}
Method 3: 
– (NSDictionary *) getDictionaryFromJsonString:(NSString *)jsonstring {
    NSError *jsonError;
    NSDictionary *dictionary = (NSDictionary *) [NSJSONSerialization JSONObjectWithData:[jsonstring dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&jsonError];
    if (jsonError) {
        dictionary = [[NSDictionary alloc] init];
    }
    return dictionary;
}
Method 4: 
– (NSString *) getStringWithPostFromUrlString:(NSString *)urlString andDataString:(NSString *)dataString {
    NSString *s = @””;
    @try {
        NSData *postdata = [dataString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
        NSString *postlength = [NSString stringWithFormat:@”%d”, [postdata length]];
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
        [request setURL:[NSURL URLWithString:urlString]];
        [request setTimeoutInterval:60];
        [request setHTTPMethod:@”POST”];
        [request setValue:postlength forHTTPHeaderField:@”Content-Length”];
        [request setValue:@”application/x-www-form-urlencoded” forHTTPHeaderField:@”Content-Type”];
        [request setHTTPBody:postdata];
        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
        if (data != nil) {
            s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        }
    }
    @catch (NSException *exception) {
        s = @””;
    }
    return s;
}
Method 5: 
– (NSString*)base64forData:(NSData*)theData {
    const uint8_t* input = (const uint8_t*)[theData bytes];
    NSInteger length = [theData length];
    static char table[] = “ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=”;
    NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
    uint8_t* output = (uint8_t*)data.mutableBytes;
    NSInteger i;
    for (i=0; i < length; i += 3) {
        NSInteger value = 0;
        NSInteger j;
        for (j = i; j < (i + 3); j++) {
            value <<= 8;
            
            if (j < length) {
                value |= (0xFF & input[j]);
            }
        }
        NSInteger theIndex = (i / 3) * 4;
        output[theIndex + 0] =                    table[(value >> 18) & 0x3F];
        output[theIndex + 1] =                    table[(value >> 12) & 0x3F];
        output[theIndex + 2] = (i + 1) < length ? table[(value >> 6)  & 0x3F] : ‘=’;
        output[theIndex + 3] = (i + 2) < length ? table[(value >> 0)  & 0x3F] : ‘=’;
    }
    return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
}

Hope above code helps you, but to stop fraud in-app you must verify reciept by sending it to your own server for verification with APPLE server.