A static-analysis writeup of how Shottr (macOS, bundle id cc.ffitch.shottr) validates licenses. Observations are from the shipped Mach-O at /Applications/Shottr.app/Contents/MacOS/Shottr and the user's preferences plist. Architecture only — no bypass.
| Purpose | URL |
|---|---|
| Primary verify | https://shottr.cc/licensing/verify.php |
| Fallback verify | https://shottr-verify-license.blimps.workers.dev |
| Restore | https://shottr.cc/restore.php |
| Purchase landing | https://shottr.cc/purchase.html |
| Upload (per-user) | https://gtfrog…lambda-url.eu-central-1.on.aws/?token=… |
| Update manifest | https://shottr.cc/api/version.json?anticache=… |
| Telemetry | https://tel.shottr.cc/telemetry.php |
The string License checking, first URL failed ( confirms primary-then-fallback. If shottr.cc is down, the Cloudflare Worker still answers, so users do not get locked out of the app due to a single point of failure.
Swift symbol: verfiyLicenseOnline(_:type:whenReady:). The misspelling ("verfiy" vs "verify") is baked into the symbol table, so it predates the shipped binary. Called from:
clickActivate: — Preferences > License > Activate button.clickRestoreLicense: — after pasting a key recovered via the restore page.restore(json:active:) — handles the JSON response on restore.Other relevant Swift symbols: PrefLicenseViewController, KeychainSwift, QueueKeychainAccess, mainAppService.
License data is stored via a KeychainSwift wrapper under a mainAppService service identifier. Diagnostic strings tell the story:
File: ~/Library/Preferences/cc.ffitch.shottr.plist. Relevant keys:
backupXorKey.Architecture: keychain first, plist as fallback if the keychain read is denied (sandbox lockdown, permission UI dismissed, etc.).
Server response is JSON. From the binary you can see the shape:
tier field returned (strings: tierL, tierM, psa_tier, Tier not returned).active boolean — second parameter to restore(json:active:).License has changed, tier stayed the same implies periodic re-validation that compares server tier against the stored one — useful for forward-rolling new feature gates without a binary update.There are no Paddle / Gumroad / FastSpring / LemonSqueezy / Stripe strings in the binary. There is no StoreKit / IAP. It is a plain license-key model, vendor-hosted.
tfLicense and clicks btnActivate (PrefLicenseViewController).verfiyLicenseOnline POSTs the key to shottr.cc/licensing/verify.php.shottr-verify-license.blimps.workers.dev.{active, tier, …}.kc-license backup written to the plist.License is checked, UI shows Thank you for activating Shottr!, gated features unlock.clickRestoreLicense: opens shottr.cc/restore.php in the browser.verfiyLicenseOnline → restore(json:active:) path as activation.The app holds enough state in Keychain to self-validate offline at launch. Periodic re-checks reconcile tier changes (License has changed, tier stayed the same) and detect explicit revocations (License was removed, License information lost, Shottr: no valid license provided).
verify.php returns.verfiyLicenseOnline) is the kind of cosmetic detail that survives years in a codebase — evidence this binary is built straight from a long-lived Swift source tree, not generated.