Licensing
A paid tweak can check whether it is licensed, though nothing forces it to. It runs inside someone else's process with no network guarantee and no app running alongside it, so the decision is made from a file on disk that the store signed.
The receipt
After a purchase is activated, the store writes a receipt to
/Library/TweakInject/Receipts/Entries/<packageID>.receipt.
It names the package, the machine it was issued for, and when it expires, and
it carries a P-256 ECDSA signature over those three values.
The tweak checks three things, and all three must hold:
- The signature verifies against a public key compiled into the tweak. The private half never leaves the store, so a receipt cannot be written by anything else.
-
The machine matches. The receipt binds to a hash of this
Mac's
IOPlatformUUID, so copying the file to another machine produces a receipt that verifies but does not apply. - It has not expired. Receipts last 60 days and are renewed weekly by a background agent. A refunded or deactivated licence simply stops being renewed, and the tweak goes inert when the lease runs out.
Worth being plain about: someone can copy a tweak's files before refunding. The 60 day lease is what handles that. The copy keeps working until the receipt expires, and then stops.
The simple check
Include the header and call
TILicenseCheck_inline
with your package identifier.
#import "TILicense.h"
__attribute__((constructor))
static void init(void) {
if (!TILicenseCheck_inline("com.example.mytweak")) return;
// ... install hooks here
}
This works, and it is also the first thing anyone patching your tweak looks for: one branch decides everything.
Making the check harder to remove
TI_Support ships macros that spread the decision through your code instead of putting it all on one line.
Dispatch instead of branching
TIL_DISPATCH calls
your function when the licence is valid, and a harmless do-nothing stub when
it is not.
TIL_DISPATCH("com.example.mytweak", install_my_hooks);
Hooks that only install when licensed
TIL_HOOK installs a
hook only when the licence is valid. Without one the hook is never installed
at all, rather than installed and then quietly doing nothing.
TIL_HOOK("com.example.mytweak", target_fn, my_replacement, &orig_fn);
Guarding data pointers
TIL_GUARD_PTR
passes a pointer through when licensed and scrambles it when not, so an
unlicensed copy crashes when it tries to use it rather than carrying on with
real data.
The reference for each macro is under TI_Support.