Articles

MASReceipt Validation for Direct Sale Apps

By Rick Fillion

License validation of applications purchased through the Mac App Store is achieved by requesting and validating MASReceipt files. It's a rather nice system, fairly simple to implement, and reasonably secure. However, validating MASReceipt files is not something that should strictly be the domain of apps distributed through the Mac App Store. If you distribute a Mac app on and off the App Store, then you should consider using a user's MASReceipt file as a valid license file for the Direct Sale build of the app as well. There are a few reasons for this:

  1. The Mac App Store is run with rules that can (and do) change over time. You never know if one day your app will fail to comply to their rules. An example of this would be the sandboxing requirement that caused a fair number of apps to abandon the Mac App Store. Most of those apps had Direct Sale equivalents, but most developers were left without a good way to transition those users from the MAS licensed version.

  2. You aren't in control of release dates on the Mac App Store. Pushing out emergency bug fix versions can't always be done on the timeframe you'd like. The time between when you've created a build that fixes a very serious issue and when it becomes available on the store can feel like an eternity. By accepting their MASReceipt as a license file, you can tell users to download the version on your website significantly faster and keep them happy.

  3. Some apps have more features in their Direct Sale equivalent, mostly due to sandboxing requirements, and private API use. Having the user pay again to gain access to those features is unfair. Having the user prove that they bought the MAS version of the app to receive a free license is time consuming.

We decided it was important for the apps we shipped to include this ability whenever possible. Our method for doing so is based on a blog post by Daniel Jalkut. Let's take a look at how we do it.

MASReceipt Validation Basics

At its most basic, the process of validating an app from the Mac App Store boils down to a few simple steps:

  • Check for the presence of the receipt. If not present, request it from the system.

  • Once you have a receipt, ensure that it's appropriately cryptographically signed.

  • Compare the information in the receipt against what you would expect. There are three pieces of data that are useful here:

    1. The Machine GUID. This ties the receipt to specific hardware.

    2. The bundle identifier. This ties the receipt to the specific app.

    3. The app version.

That's really about it. If any of the checks fail the app should terminate immediately by exiting with an exit code of 173. OS X knows that if an app exits with 173 that it should try to get a new receipt for that app.

If you've never implemented receipt validation for the Mac App Store, I recommend you read Apple's Validating Mac App Store Receipts documentation for a more detailed look.

Making Receipts Available to Direct Sale Builds

The most important part of this whole process is simply making sure that the receipt file will be available to the Direct Sale build when needed. MASReceipts are stored within the app bundle itself, and so by the time the user has installed a direct build, they will likely have overwritten the MAS build along with its receipt. Therefore you should not assume that the MAS build's original receipt will be present on the system.

The solution to this is quite simple. Upon successful validation of the receipt in the MAS build, the receipt file should be copied to a location that's known to both builds. For example, ~/Library/Application Support/${AppName}/MASReceipts/${MachineGUID}.

There are a few things to note here:

  • The location of ~/Library/Application Support/ might be different if one build is sandboxed and the other is not. You might require additional sandboxing exceptions for this location.

  • The important part is to have a deterministic file path. This could easily be achieved with a static file name, but by naming the file based on the Machine GUID, you automatically gain support for multiple hardware. This would be useful for users who use features like Target Disk Mode, and other common scenarios.

Validation in Direct Sale Builds

The process of validating the receipt in the direct build is very similar the process the MAS build would take, but it has some important differences.

For starters, instead of looking inside of its own bundle, it should be looking for the presence of the receipt at the location where the MAS build saves it. Once it has the file it can go about the usual checks.

In the event that you use different bundle identifiers for your builds, you'll want to the direct build to know about the MAS build's identifier and compare against that instead of its own.

One check is likely to fail though - the version number will almost assuredly mismatch. The most obvious case for this is the use case of a 2.0.0 user experiencing a crash that you've fixed in 2.0.1. You'll be recommending that they download 2.0.1 from your website until Apple reviews your new binary, however their receipt will be for 2.0.0.

There are a few solutions to this. You could simply skip the version check. We chose to simply make the version check fairly loose. For the time being, direct sale builds check for matching initial digits, so any 2.x receipt should match on a 2.x build.

Performing Validation

Receipt validation of MAS apps generally happens as a part of the launch process, whereas direct sale apps might check at launch but usually need to do additional checks to decide whether to show UI elements specific to a trial. We do the shared receipt validation along with the standard license checks, and in fact the app checks first for a receipt before checking the normal licensing (AquaticPrime on our case).

This should go without saying, but naturally once you've validated the receipt you should remove any restrictions that your app might impose on unlicensed users. Beyond that, you should actively make it difficult for the user to accidentally re-register the application through your direct store. In our case, if the user visits the registration window we show a special version of it to indicate that their receipt was used for validation.

KaleidoscopeRegistrationWindowMASReceipt.png

Everyone Wins

I hope that this blog post has convinced you that your app should accept Mac App Store receipts as a valid license even for your non-MAS builds. Besides the few rather minute gotchas, it's quite straight forward to implement, and provides for a good way to please users by allowing them to get fixes to their problems faster. The fact that it also protects you against future unknowns on the Mac App Store is also extremely convenient.