I'm trying to validate that the receipt is for this particular device using the code from a popular library for Receipt Validation called RMStore:
NSUUID * uuid = [[UIDevice currentDevice] identifierForVendor];
uuid_t uuidBytes;
[uuid getUUIDBytes:uuidBytes];
NSMutableData * data = [[NSMutableData alloc] init];
[data appendBytes:uuidBytes length:sizeof(uuidBytes)];
[data appendData:_parsedReceipt.opaqueValue];
[data appendData:_parsedReceipt.bundleIdentifierData];
NSMutableData * computedHash = [NSMutableData dataWithLength:SHA_DIGEST_LENGTH];
SHA1(data.bytes, data.length, computedHash.mutableBytes);
return [computedHash isEqualToData:_parsedReceipt.hash];
But the two hashes are not equal. Is there something wrong with the code?
Edit
SKReceiptRefreshRequest * request = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:@{SKReceiptPropertyIsRevoked: @YES}];
[request setDelegate:self];
[request start];
After I re-fetch the receipt once, the hashes start to match. This is the most bizarre behavior I have seen. Does anyone have an idea why this may happen?
As indicated in the answer from where you took that code, Apple recommends to refresh the receipt if validation fails. This is what RMStore
does to validate a receipt/transaction:
RMAppReceipt *receipt = [RMAppReceipt bundleReceipt];
const BOOL verified = [self verifyTransaction:transaction inReceipt:receipt success:successBlock failure:nil]; // failureBlock is nil intentionally. See below.
if (verified) return;
// Apple recommends to refresh the receipt if validation fails on iOS
[[RMStore defaultStore] refreshReceiptOnSuccess:^{
RMAppReceipt *receipt = [RMAppReceipt bundleReceipt];
[self verifyTransaction:transaction inReceipt:receipt success:successBlock failure:failureBlock];
} failure:^(NSError *error) {
[self failWithBlock:failureBlock error:error];
}];