Software Development

It has been I-don’t-even-know-how-long (that is: an eternity) since I last offered any of my apps for purchase outside of the App Stores.
GimmeSomeTune was donationware (handled by PayPal), but there was no licensing, so that doesn’t count.
For a software-bundle (I can’t remember the name, and I don’t believe it’s around anymore), I created a non-updatable version of ScreenFloat 1.x that customers received, yet also without licenses, so that doesn’t count either.
I think the only app I ever really sold properly and had a license scheme for and handled sales myself was flickery, which I sold from my website through PayPal before the Mac App Store arrived.
But once the Mac App Store hit, I transitioned all my apps to it pretty much right away.
It’s just so convenient: no license creation, no license verification (apart from receipt validation, but that has become more convenient recently), easy updating, no handling of payments, invoices, refunds, and the potential of getting featured to lots and lots of users.


Why do it, then?

Besides all that, it was high time I set up a way to also sell my apps outside of the Mac App Store.
Without a licensing system for my apps, I’ve been unable to participate in software-bundles and/or collections. Lots of companies and corporations cannot purchase apps from the Mac App Store due to policies. Individuals who want to purchase my apps for work are unable to do so because of those same policies.
And while I am a strong proponent of the Mac App Store, I also believe in giving people a choice. Customers should have the choice of purchasing my apps on the App Store, or directly* from me. *: I don’t handle any of the payment and invoicing myself, that’s done by my Merchant of Record, Paddle.
Also, it certainly cannot hurt to have an alternate route to sell my apps.
What if the Mac App Store goes belly-up? Not likely, but still, I’d go belly-up along with it.
What if Apple doesn’t want my apps anymore? It could happen (it has been close before), and then I’d be screwed.

All that is just a long-winded way of saying: it makes sense to have some redundancy. A second way of selling my apps. One I have a bit more control over.

Now, I did slack off on this for a long time. I’ve been getting requests to participate in bundles for years (!) and still couldn’t bring myself to set it up. I don’t know why. I guess I thought my time was better spent working on my apps instead of backend stuff.
But then there were all these recent inquiries from companies, and users affected by policies of companies, who cannot purchase apps from the Mac App Store. For some reason, there’s been an uptick there, and requests have become more and more frequent.
So I hunkered down and finally started looking into all the things that needed to get done so I could sell my apps outside of the Mac App Store as well:

  • Decide on a Merchant of Record
    (crucial for the “selling” part)
  • Come up with and implement a license key scheme
    (crucial for legitimating purchases of my app)
  • Freshen up my PHP, HTML and JavaScript “skills” and integrate my backend with the merchant’s
    (crucial for everything)
  • Implement a way for the app to update itself
    (pretty much standard nowadays)
  • In that vein, implement a safer way to download files than just a plain file-straight-from-server download
    (so the app can verify the update is legit)

Getting a Merchant of Record

A “Merchant of Record” is a company that handles payments, invoicing, refunds, taxes, etc for indie software developers and other businesses.
There are actually quite a few to choose from: FastSpring, PayPal, Paddle, Stripe, and Gumroad, just to name a few.

  • PayPal I didn’t want to use because I remember its API from back in the day and it just gave me headaches. I’m actually amazed I pulled it off for flickery way back when. Also, and I might be wrong about this, but, I believe it still doesn’t handle taxes and stuff for you, and I just won’t do that myself anymore.
  • Gumroad seemed to me like more of a hobby thing? Anyway, I couldn’t see myself selling software through them.
  • FastSpring is a popular choice, loved for its extensive feature set.
  • Stripe seemed out of my league. Like, it’s a fancy masquerade ball, and I’m in the dark corner wearing sweats, eventually getting asked to leave because I make people “uncomfortable”.
Put the Paddle to the Metal

So I went with Paddle. I don’t feel frowned upon here in my sweats. And in my calculations, it seemed a bit less expensive than FastSpring. Plus, I’ve heard good things about it. The API is well-documented* and their support seemed… supportive.
Why’s there an ominous asterisk next to “well-documented”? I’m glad you asked!
There’s Paddle Classic, and as of recently, there’s the new Paddle Billing, with a completely different API.
Guess what this idiot (read: me) did. Yup, I spent 3 days looking into and partially implementing Paddle Classic, only to find out it’s no longer available for new signups. Fun!
Hey, Paddle, I have a suggestion: Instead of that tiny, friendly light-blue indicator at the top of the Paddle Classic API documentation page that you can easily overlook and even dismiss, why not make it a big, red, bold-letter banner? That would have saved me tons of time.
Instead, I sat there wondering why none of my test-calls from the Paddle dashboard worked. (Side note: Debugging remote PHP scripts is a freaking pain. Especially the way I do it – which might be the wrong way.)
But that’s alright. Every story needs its ups and downs. Why not begin with a down outright? Who knows, it could be all uphill from here!

For selling through Paddle, you need their approval. They take a look at your website and make sure everything’s on the up-and-up regarding your Privacy Policy, Terms of Service, payment flow, checkout and whatnot.
The entire process was fairly straight-forward. It might have helped that I’m already selling my apps through the Mac App Store, so they could see that I’m serious about my endeavors. For my Terms of Service I looked into the websites of other indies selling software through Paddle, which I thought made sense, since they’re already approved by them.
It took about three weeks with a bit of back and forth to get the approval, but that was no time lost, since I used it to start implementing the correct API on the backend.


Scheming up a License Key

A vital part of an app sold outside of the Mac App Store is requiring the user to have a license key in order to keep using it past its trial limitations. If you don’t have that, anyone could just use your app without paying for it. That’s fine for freeware or donationware and the like, but for an app you want to sell, it’s counterproductive.

Obviously, you want to be the only one able to create these license keys. Back in the day, for flickery, I had a very traditional format: a 32-odd-character dash-separated string, like FLKRY-ABA1-ABA2-ABA3…
It was just a salted MD5 hash of a certain order of transformed and salted md5 hashes of the customer’s name and email. In the app, the user would enter their name, email and the license key and flickery would re-create the license key itself from the supplied info and see if it matches up with the one the user supplied. If it did, the app was registered, if not, then not.
In order to forge a key, one would have to know the salts, the transformations and the order I used to create a valid key. Someone with a lot of time on their hands could eventually figure it out and create a key generator. Or hack the flickery binary and figure it out that way.
The salts were actually more pepper than salt, as they were hopefully secret. As a side note, I don’t think the license generation was ever cracked. The app itself was, though.

I’ve decided to go a different way this time around. The license now is a cryptographically signed payload (signed using a private key), consisting of the user’s data, app information and transactional data. All the app does is use the corresponding public key to verify the signature. If it’s valid, it can proceed with further activation steps. If not, something’s wrong with the license. As long as the private key actually stays private, there’s no feasible way to forge a license at this point in time.

I also wanted to make sure a license can only be active on a limited number of Macs or user accounts at a time, and have a way of blocklisting license keys infringing on my Terms of Service.
This is also where license types come into play.
There’s the “personal license” for individuals, which can be used to activate the app a limited amount of times (on any Mac or user account);
and the “commercial license”, which can be activated on a single Mac, but used with an unlimited amount of accounts on that Mac – a “seat” license.
With managing and limiting the activations comes the need to unregister individual copies of an app, or reset the entire license, so you can free up a slot to activate the app on a different Mac or user account. More work on the backend!

Consequently, in order to activate a copy of my app with a license key, an internet connection is required. But you also need an internet connection to download the app in the first place, so I don’t see a downside there. And there’s no always-online requirement. Only once in a while, the app will demand a connection to make sure the license and its activation are still good.

What was important to me about all this though is that none of the user’s information, not even the license key, is stored on my server. Yes, Paddle stores user data, because they have to. But I didn’t see the need to have user data be present on my server as well. It holds only the information it absolutely requires to activate, deactivate, reset, re-issue and refund licenses.

Most of this is handled on the backend, which took most of my time to implement and test. Even though I have been using PHP (with MySQL for database integration) on and off over the years, I’m by no means “fluent”, so I repeatedly had to consult different guides to figure out the best practices, and how to code safely, for everyone involved. JavaScript I’d never really used before (but had to for the Checkout pages), and HTML with CSS, well… my checkout pages are as pretty as they’re going to get, to put it bluntly.
But I learned a lot. I like doing server/website stuff for some reason. Maybe because it’s not my area of expertise, and I get to understand the workings of the internet a little bit better and learn so much. It just has a certain allure I can’t explain.


Next Time

In the next part, I’ll go over the integration with Paddle, and my backend implementation. I hope you’ll join me!


Read more

If you’re using Yoink on macOS Sequoia, you might have encountered an issue where Yoink would not accept any files anymore:

Or if you’re using Transloader on macOS Sequoia, you might find your Link- and File Actions not working correctly:

Basically any app that handles file URLs and saves them as a security-scoped bookmark for later access can be bitten by this bug, currently occurring on macOS 15.0 and 15.0.1.

This is caused by a bug in the macOS daemon process called “ScopedBookmarkAgent”, according to a CoreOS engineer on macOS, as stated on the Apple Developer Forums:

What you’re hitting is bug in “ScopedBookmarksAgent” [sic] which can cause it hang if it happens to have been launched when the keychain was also locked (for example, late in the screen lock process). That bug is fixed as of macOS 15.1 beta 4.

– DTS Engineer, CoreOS/Hardware

The downside is that 3rd party developers like myself cannot fix this in their apps. Apple has to, in macOS.
The upside is that with macOS 15.1, the bug will reportedly be fixed and things should work as they used to.


As a temporary workaround, you can:
– Quit Yoink (or any other afflicted app)
– Using Activity Monitor.app, quit the ScopedBookmarkAgent process
– Relaunch Yoink (or any other afflicted app), and it should work again (for a while)


My apologies for the inconvenience. Here’s to hoping macOS 15.1 will be released soon.

Cheers,
– Matthias

Read more

For my screen-capture all-rounder app ScreenFloat, I’ve received feedback from users that, under macOS Sequoia, their keyboard shortcuts suddenly stopped working.

Well, with macOS 15 Sequoia comes an undocumented change that boggles the mind (and which developers have never been told about during the macOS upgrade’s beta period) :
In 3rd-Party-Apps, users are no longer allowed to set up keyboard shortcuts that use only the option ⌥, only the shift ⇧, or only option + shift ⌥ ⇧ keys as the modifier (like ⌥ ⇧ 2).

Why? As an Apple Frameworks engineer puts it, “to limit the ability of key-logging in malware”. A make–shift reason, if you ask me (or the other developers in that thread):

I also don’t get the logic. The change only impacts sandboxed apps, but malware wouldn’t use sandboxing. Plus, any app can request input monitoring and misuse it, so this mostly hurts legitimate apps and their users, and does very little to stop actual malware.
– sindresorhus

That’s sadly something that’s becoming more and more routine at Apple: punish developers that adhere to the sandbox and Mac App Store rules, for no good reason.

How does this even prevents key loggers?
– IzsakSVK

Beats me (and Apple).

Of course, as always, Apple’s own software is exempt from this restriction, as you can see in this screenshot of System Settings > Keyboard > Keyboard Shortcuts, where I could set it up just fine.
Why this matters? Consistency. Users expect that if it works in Apple’s software, it should also work in other apps they use. And I agree!

Just yet another change where Apple oversteps its bounds to prevent users from configuring and using their own computers how they want to.

Read more

macOS 15 Sequoia introduced a new, annoying screen capture permission reminder that has brought on a lot of push-back from developers (myself included).

Now, Ricci Adams has found a way to virtually stop the nagging for specific apps. (I found out about this from Jeff Johnson’s Desolation of Blog blog).

First things first: Please use your own discretion when trying this. Consider if you’re savvy enough to work with the Terminal, and if you really want to remove the permission reminder for an app.

Apparently, there is a TCC (Transparency, Consent and Control) – protected file that keeps track of when to show the next nag screen for specific screen capturing apps, located at

~/Library/Group Containers/group.com.apple.replayd/ScreenCaptureApprovals.plist

Using Terminal (which first needs to be granted Full Disk Access in System Settings > Privacy & Security), you can set that date far into the future so you won’t ever see the nag again.

For example, I wanted to make absolutely sure it never bothers me again for my own app ScreenFloat, so I just set it to my retirement date: January 1st, 4321.

defaults write ~/Library/Group\ Containers/group.com.apple.replayd/ScreenCaptureApprovals.plist "/Applications/ScreenFloat.app/Contents/MacOS/ScreenFloat/" -date "4321-01-01 00:00:00 +0000"

Restart your Mac (or log out and back in) so it accepts the new defaults, and you’re all set.

Read more