AppStore VerifyReceipt in Corona Store object?

I just watched the WWDC 12 video on in-app purchases. I’m confused as to how I’m able to verify a receipt through Corona’s Store object. Does this happen automatically? I do not see a mention of the VerifyReceipt method as detailed in the Apple in-app purchases video. When the Apple engineer stepped through the process, each and every time a purchase was made, he suggested to verify the receipt with Apple’s server before granting permission to what ever was purchased. Does anybody know how to verify a receipt?

Secondly, how will we know when a purchase is cancelled on an unexpired receipt?

Here is a link to the video I’m referring to (need to be logged in to Apple’s dev center to view):
https://developer.apple.com/videos/wwdc/2012/?include=308#308

Note: I posted this under the Apple In-App purchase tutorial but it appears the comments are now closed.

thanks in advance.

[import]uid: 38348 topic_id: 35094 reply_id: 335094[/import]

I wrote a library for verifying auto-renewable in-app purchases…
Here it is

It wouldn’t be too difficult to modify the code for verifying ordinary in-app purchases as well… [import]uid: 64174 topic_id: 35094 reply_id: 139537[/import]

Satheesh, that’s great. I’ll check it out.

I’m just getting started with the Corona Store object and In-App purchases. Does Google Play have this same setup in which you can verify purchases? If so, does this API support Google Play verify receipt?

thanks
[import]uid: 38348 topic_id: 35094 reply_id: 139570[/import]

@sondlerd Sorry, I have no idea.

I wrote a library for verifying auto-renewable in-app purchases…
Here it is

It wouldn’t be too difficult to modify the code for verifying ordinary in-app purchases as well… [import]uid: 64174 topic_id: 35094 reply_id: 139537[/import]

Satheesh, that’s great. I’ll check it out.

I’m just getting started with the Corona Store object and In-App purchases. Does Google Play have this same setup in which you can verify purchases? If so, does this API support Google Play verify receipt?

thanks
[import]uid: 38348 topic_id: 35094 reply_id: 139570[/import]

@sondlerd Sorry, I have no idea.

hi satheesh,

i am using your script for client side validation for regular iAP purchases. when in sandbox mode, but sending to productive receipt server from apple, i get correctly the error 21007. but your script crashes in the event listener, so i dont get a callback.

the decoded.receipt is nil, therefore the decoded.receipt.product_id call fails.

did you fix that, or are you aware of it?

best,

digi

@dingo

The 21007 error’s description is :“This receipt is a sandbox receipt, but it was sent to the production service for verification.”

So you will have to validate an actual production receipt. i.e make an actual in-app purchase and validate that receipt.

hi satheesh,

thanks, but this was not the point. I just wanted to let you know that if this error gets raised, your listener crashes and the listener set in validate.start won’t get called. i fixed it, i just wanted to let you know.

Oh… ok ok! 
Can you post your fix here? I will update it in git. 

And thanks for pointing that out.  :) 

I dont have the code here right now, so i try to pseudo it from your git code.

 local function localListener(event) local response = event.response local decoded = json.decode(response) if type(decoded) == "table" then event.iTunes\_StatusCode = decoded.status --receipt data if(event.iTunes\_StatusCode == 0 or event.iTunes\_StatusCode == "0") then event.identifier = decoded.receipt.product\_id; event.bid = decoded.receipt.bid; event.iTunes\_Response = decoded; event.iTunes\_StatusCodeDescription = errorMap[tostring(event.iTunes\_StatusCode)]; else event.identifier = ""; event.bid = ""; event.iTunes\_Response = tostring(event.iTunes\_StatusCode); event.iTunes\_StatusCodeDescription = "21007"; end end listener(event); end network.request(link,"POST",localListener,{body=postData})

I think you get the idea, if there is an error, the decoded.receipt.product_id call fails. sorry for the noobish code!

I just post the code I use here (IOS only). Remember to store your receipt somewhere safe - I use AES coding and store it in a file on the device. Its not 100% hacker proof, but at least they can´t read my stored data.

Here is the code snippet that I use to check for premium subscriptions (cut-n-paste):

function validateListner(event) --json-decoded itunes Response storeResponse=json.decode(event.response) print("Validation status:"..storeResponse.status) --print("Restore table:"..table\_print (storeResponse)) -- Must go through receipt records to find important values: local idex=0 for key, value in pairs (storeResponse) do idex=idex+1 if type (value) == "table" then --print(idex..". "..key.." is a table") if key=="receipt" then -- Third record is usually the receipt table (but no certainity of that): local idex2=0 for key, value in pairs (value) do idex2=idex2+1 if key=="purchase\_date" then --scoreitems[6]=makeTimeStamp(lastchecktime) RestorePurchaseDate=string.sub(value,1,19) end if key=="expires\_date\_formatted" then RestoreExpiresDate=string.sub(value,1,19) end if key=="product\_id" then RestoreProductID=string.sub(value,1) end if key=="quantity" then RestoreQuantity=tonumber(value) end end end -- elseif "number" == type(key) then -- print(idex..". "..key.."="..tostring(value)) -- else -- print(idex..". "..key.."="..value) end end print("purchasedate:"..RestorePurchaseDate) print("expiresdate:"..RestoreExpiresDate) print("quantity:"..RestoreQuantity) print("id:"..RestoreProductID) if RestoreProductID=="com.yourcompany.yourgame.yoursubscription" then -- receipt for current subscription obtained. Check further: if RestoreQuantity\>0 and tonumber(storeResponse.status)==0 then -- more than zero products purchased and valid, so keep premium on: premiumon=true print("premium on!") premiumchk=premiumchk+1 else print("subscription not active..") premiumoff=premiumoff+1 -- May be active in another record.. end end end -- for testing: --premiumreceipt=fromhex(\*\*\*\*\*) \<-- Put a real reciept here to test (paste it from console during sandbox testing) if premiumreceipt~=nil then --if premiumreceipt~=nil then premium has been purchased so -- Check subscription (if still within subscription period) validate.start { receipt = premiumreceipt, password = \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*, -- Your store secret here listener = validateListner, testing = testingproduct, --Should be true if you use sandbox receipt, false if you use actual receipt } validtimer=timer.performWithDelay(5000, function() if premiumoff2==premiumoff then if premiumchk\>0 then premiumon=true timer.cancel(validtimer) elseif premiumoff\>0 then print("premiumon switched off by premium receipt check") premiumon=false timer.cancel(validtimer) end else premiumoff2=premiumoff end end,10) end

The code will go through all the responses from the store; E.g. even if you supply only the last recipe, iTunes store will respond with multiple transactions (if the user made several). In sandbox mode during testing it can easily become 50+. Change test account if you want to get clear of all those old transactions.

For subscriptions you want to check the purchase date and expiration date. Add the days for all those transactions and check with current date (Use first purchase date from all the valid ones to see how many days have passed with an subscription).

Hope it helps you!

What are you using to provide the AES encryption?

How are you protecting your key?

AES lua con be found here:

https://github.com/bighil/aeslua

Just remember to use the bit plugin that is integrated in corona or it will be quite slow.

Base64 implementations; well just google it and use one of them.

The key must be stored, but you can try to hide it as an AES coded string. It will never be 100% hacker proof anyway as long as you store the receipt on the device. If the program can decode it, so can a hacker as well, but it is more difficult than using plain text.

Thanks for the link.

How are you storing your key?

Also, how are you declaring your app with Apple, are you filing for a certificate for encryption?

Yes, you must sign off that the encryption is only used to store game specific data and then its ok apparently. My game “Smartball: gravity games” just hit the app store and it uses AES. You can look at the files it generates yourself and tellme what you think?

You don’t file with the government to register the app?  I haven’t done it with Apple but I was under the impression any encryption had to file the government paperwork.  I created my own encryption lib, it’s more complex obfuscation but it thwarts 99.99% of people with no need to deal with keys or encryption approval.

I can’t find the app on the app store. I assume your just saving the key somewhere on the file system without encryption and likely renaming it or something?  Unless the end user is bringing something to the table (like a password or one time that protects the key) it is likely just sitting there ready to unlock the encryption. Or you use the same passphrase to unlock the key (if it is encrypted) to then unlock the encryption.

hi satheesh,

i am using your script for client side validation for regular iAP purchases. when in sandbox mode, but sending to productive receipt server from apple, i get correctly the error 21007. but your script crashes in the event listener, so i dont get a callback.

the decoded.receipt is nil, therefore the decoded.receipt.product_id call fails.

did you fix that, or are you aware of it?

best,

digi

@dingo

The 21007 error’s description is :“This receipt is a sandbox receipt, but it was sent to the production service for verification.”

So you will have to validate an actual production receipt. i.e make an actual in-app purchase and validate that receipt.