cordova-plugin-purchase
cordova-plugin-purchase copied to clipboard
(ios) On-device receipt validation/parsing
Changes proposed in this pull request (specific to iOS):
- Relates to #1170
- Enables on-device validation/parsing of app store receipts using components from the RMStore library.
- The decoded receipt payload is attached as a JSON structure to the app store receipt response alongside the base64-encoded binary version.
- Pulls in the OpenSSL library via Cocoapods to perform the cryptographic decryption operation
- Adds new
setBundleDetails()
API function to manually set bundle package name and version (rather than automatically trust the one in the app plist - see here)
- The decoded receipt payload is attached as a JSON structure to the app store receipt response alongside the base64-encoded binary version.
- Supports optional success/error callbacks when calling
finish()
Reasoning:
- Firstly, this is not a replacement for the recommended server-side validation/parsing of app store receipts such as provided by billing.fovea.cc.
- If you are concerned about security and possibility of exploitation of your paid app features, then you should use server-side validation
- However, in some circumstances where the in-app products are low-value or niche, server-side validation/parsing is overkill and client-side validation/parsing of the app store receipt within the app is sufficient and easier.
- This PR adds the ability for the plugin to validate/parse app store receipts on the device; it's then the app developers choice whether to also carry out server-side validation/parsing.
TODO:
- This PR currently doesn't expose the new functionality in the JS
store
API, it just adds the functionality to the Objective-C and JS layers of the Cordova plugin API. - Maybe an option could be added to as to whether to use the output of on-device receipt parsing to update the store DB?
To test this pull request with cordova:
# 1: Uninstall the plugin (if already installed)
cordova plugin rm cordova-plugin-purchase
# 2: Install from github
cordova plugin add "https://github.com/dpa99c/cordova-plugin-purchase.git#ios_local_receipt"
@dpa99c I've read that OpenSSL adds several MB to the size of the app. Is this correct? If so, maybe the feature should be opt-in with an install-time flag?
@j3k0 yeah, the OpenSSL iOS/arm64 framework weighs in at around 20Mb.
Though I'm not sure how we'd make it an optional addition at installation time since it's included via the <podspec>
in config.xml
- the Cordova plugin mechanism doesn't really support that.
I guess we could do something similar to what I've done for the diagnostic plugin which is to run a node script on the node postinstall
hook in order to comment in/out the relevant portion of config.xml
.
Any suggestions how we could do it more easily?
Maybe the simplest solution is to maintain a separate branch? (cordova-purchase-plugin-local
for example).
I wouldn't want my app to go from under 2MB (actual size of my test app on iOS) to 22MB for a feature I don't even need (when using a server-side validator or no validation at all). Maybe we can ask the cordova team if they have any other suggestions?
Another option is to try to use the built-in iOS crypto libraries to do the pkcs7 decoding. That way we wouldn't need to include OpenSSL at all. This gist is pretty old but contains an implementation for OSX so similar libraries to iOS. Maybe there's an up-to-date fork for iOS. The RMStore library I've used is quite convenient so it might be possible to swap out just the crypto operation and use the rest of the library. I'll look into it when I get a bit of time.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
@j3k0 I've updated this PR branch onto your latest master branch and also made the inclusion of the iOS receipt validation functionality optional via a plugin variable:
By default, it will not be enabled and therefore the large OpenSSL library will not be pulled into the app build.
To enable the functionality, you must do so with a plugin variable at plugin installation time:
cordova plugin add cordova-plugin-purchase --variable LOCAL_RECEIPT_VALIDATION=true
Since some references are made to the local validation classes in the InAppPurchase
class, when the functionality is disabled the plugin includes stubs of the local validation classes to keep the compiler happy.
Hopefully this should provide a way you will consider acceptable of make the functionality available to those who want it without adversely affecting other plugin users who don't want to use it. If you have time, please take a look at the changes in the PR and let me know your thoughts.
@j3k0 I've updated the PR branch to align with latest (v13) of the plugin - any reason not to merge this now?
It's an opt-in feature so by default is disabled and the plugin will behave as it currently does, with the iOS receipt validation functionality stubbed out. It's only activated if the user installs the plugin with the specified plugin variable above. Therefore I can see no negative consequences for the existing implementation if this feature is merged.
Hey @dpa99c - this is nice.
I think this should be a separate plugin (the way braintree support is added to this plugin by installing "cordova-plugin-purchase-braintre"). This way there's no need to hack into the plugin xml file, which I think might backfire on non-pure cordova platforms (capacitor, monaca, ...)
I'm busy finalizing another project, then I will look into this right after.
@j3k0 I've tweaked the npm postinstall
script this PR introduces so it looks at package.json
for the plugin variable to activate iOS local receipt verification, and ignores any error if config.xml
does not exist.
This allows it to work in a Capacitor project (which I have tested - not sure about Monaca) by adding the following block to package.json
(which Cordova CLI adds to a Cordova project):
{
"cordova": {
"plugins": {
"cordova-plugin-purchase": {
"LOCAL_RECEIPT_VALIDATION": "true"
}
}
}
}
I looked into whether the dependency on OpenSSL could be eliminated by using the built-in iOS crypto libraries but unfortunately they don't support the PCKS7 operations required to decrypt the receipt.
As to publishing this as a different plugin, that would require keep it in sync with the main plugin which isn't something I'd have to for, but maybe someone else is willing to take on that maintenance?
why not merge this? Apple Store deprecated their [verifyreceipt], it would be good option
Hello
Do you have any working example code please ?
For Auto renewable subscription, one product only, i just need the expiry date or also the purchase data will be ok.
- Restore purchases options
cordova plugin add "https://github.com/dpa99c/cordova-plugin-purchase.git#ios_local_receipt" --variable LOCAL_RECEIPT_VALIDATION=true