How licenses work
A license for the Mac app is a small signed file, made for one Mac. Your own devices check it, with no call to us, so it works offline and keeps working for as long as that Mac has it.
You buy a license for the Mac app once, for one Mac; the headset and web clients are free. The website takes the payment and nothing else: the license is made by the Mac app. For the first 14 days the license is refundable, and during that time we can tell which purchase it belongs to — that is what makes a refund possible. After that the app exchanges it for a private license, which our server signs without being able to read it (a blind signature), so nothing we store connects a private license to a payment. The owner of a license is a key in the Mac’s Keychain, used after Touch ID: revoking a private license, or moving it to another Mac, takes that key. Our staff can cancel a license only while it is still refundable: an owner can cancel one directly, anyone else’s cancel needs an owner’s approval — owners are appointed only through a hardware key that is on no server. Once a license is private, only its owner can revoke it: no staff power over private licenses exists or is planned.
The limits of this system cost us, not you. A patched app, or a license copied from a Mac without a security chip, is a sale we did not make. If our server were ever taken over, the intruder would find no names, no addresses, no private licenses and nothing that ties a license to the person who bought it; they could not appoint staff or get the apps to trust a new key. What they could do is sign licenses for free until we distrust the key they found — lost sales, not lost privacy. Each limit is listed on this page, with what bounds it.
The Hitchhacker’s Guide to the GUI, Entry 1: Licenses · 3 min 17 s · captions on. The pictures were made with AI tools and are illustrations; the page below is the exact description.
- 0:00 The Hitchhacker'S Guide To The Gui
- 0:09 Most licenses know who you are.
- 0:21 The website takes the payment. That is all it does.
- 0:35 First license: refundable.
- 0:51 Second license: signed blind.
- 1:22 The owner is whoever holds the key.
- 1:32 Checked offline: "Sign this."
- 1:55 One license, one computer. Moving is free.
- 2:06 Who watches us?
- 2:29 The limits cost us, not you.
- 3:01 Built, or planned? The page below says which.
Transcript
This is the Hitchhacker's Guide to the GUI: a reference for people who would like their software to mind its own business.
Entry one. Licenses.
Most software licenses work like a hotel wristband. It proves you paid. It also tells the front desk where you are,
what you ordered, and when you went to bed. We thought this a bit much for a small app.
So here is what happens when you buy Cody. The website takes your payment and hands your computer a ticket, good for exactly one license.
That is the website's entire job. It does not write the license, and it never sees the one you end up with.
Your computer writes its own license and sends it in to be signed. This first one is refundable.
We keep a note matching it to its payment, and nothing else: no name, no email, nothing about you.
That note is how we are able to give you your money back.
Meanwhile, your computer prepares a second license and seals it in an envelope lined with carbon paper. When the refund window closes,
it sends us the envelope. We sign the outside. The signature presses through onto the license inside.
We never open it. The first license is canceled, the second takes its place,
and from then on we cannot tell which license is yours. This is called a blind signature.
It is standard, published mathematics, and not, as it sounds, a party trick.
Who owns the license? Whoever holds its key. The key lives in your computer's keychain, behind your fingerprint.
Not in an account, because there isn't one.
Each license also names one particular computer, by a key locked inside that computer's security chip.
When your headset wants to know whether this computer is licensed, it does not ask us.
It hands the computer a random number and says: sign this. Only that one computer can.
No internet required, which is convenient on airplanes and in sheds.
Copy the license file to another computer and nothing happens, which is the point.
Get a new computer, and you move the license over yourself, free of charge.
A second computer would like a second license.
And who keeps an eye on us? Staff powers are licenses too, all chained to a single hardware key.
Staff can cancel a license only while it is still refundable, and only with an owner's approval.
Once your license is private, only you can revoke it.
The keys that sign licenses are replaced every few months, and your apps trust a new one only after an owner has approved it.
Now, the limits, which have the decency to cost us rather than you. Someone who rewrites the app can make it skip all of this,
and a computer too old to have a security chip keeps its key where a determined person could copy it.
Either way, that is a sale we did not make.
And if our website were ever taken over, the intruder would find no names, no addresses, and nothing that ties a license to the person who bought it.
They could hand out free licenses until we noticed and retired the key.
Annoying for us. Uneventful for you.
As of October 2026, some of this is built and tested, and some is still on the drawing board. The page below says which, piece by piece.
That concludes this entry. The next one concerns how Cody keeps your computer yours.
Status on October 1, 2026: nothing described here is in a customer’s hands yet. The site’s side and the web client’s check are written and tested in code; the Mac app’s side is being written. No signing key exists, nothing sells a license, and no app requires one: the web client asks a Mac for its license and only records the answer. Every diagram and every table row below says which of three states it is in.
The design changed on October 1. In the first version (stage 1) the buyer’s
browser made the licenses and a website passkey owned them. That path exists in code, with tests, and is being
retired, because a page on the site’s domain can always ask a website passkey for its key — and whoever takes
over a site decides what its pages do. In the current design the Mac app makes and holds the license: its code
is signed with a key no web server holds, and macOS checks it before it runs. Everything the Mac app does in
that design is tagged Designed below. The site’s and the web client’s side of it is built and tested —
services/www/test/license-mac.test.mjs makes the Mac app’s calls the way the app will — and is
tagged Built, as is what stage 1 built and the current design still uses.
- BuiltThe code exists and has automated tests. It is not live: no signing key has been made.
- DesignedWritten down and agreed. No tested code yet; some of it is being written now. In the diagrams these parts have a dashed outline.
- LaterNoted for later. No agreed design.
On this page
- Buying
- Going private automatically
- Checking a license offline
- Revoke, move, and the two lists
- Staff powers are licenses too
- Signing keys
- What the site can connect
- Who could attack it, and what they get
- Test evidence
- Not built yet
What it is made from
No cryptography here is our own. These are the parts, by their names.
| Part | What is used | Status |
|---|---|---|
| The signature on a license | RSA blind signatures, RFC 9474, variant RSABSSA-SHA384-PSS-Randomized, through Cloudflare’s @cloudflare/blindrsa-ts 0.4.6 (pinned to that exact version). Checking one is ordinary RSASSA-PSS with SHA-384. | Built |
| Key size | RSA, 3072 bits by default (about 128-bit strength); 4096 is accepted too. A new key each quarter is what limits a leak, not the size. | Built |
| The owner key | Ed25519. One random key pair per license, made by the Mac app and kept in the Keychain (synced through iCloud Keychain); every use asks for Touch ID or the Mac’s password first (LocalAuthentication). The site checks its signature on a conversion order and on a revoke against the key inside the license. | Built the format, the site’s checks Designed the Mac app’s keys |
| The Mac key | ECDSA with P-256 and SHA-256. The public half is a field of every license, covered by the signature; a license without one is refused. To show that it holds a license, a Mac signs a fresh 32-byte challenge from the headset or browser, together with the license’s id and the Mac’s own identity key. As designed the private half is made inside one Mac’s Secure Enclave and cannot leave it; a Mac without a Secure Enclave keeps it in the Keychain, which is weaker. | Built the field, the proof, the web client’s check Designed the Mac’s keys and its answer, the headset’s check |
| Stage 1’s owner: a website passkey | WebAuthn, user verification required, with the PRF extension where the browser and authenticator have it; signatures ES256, RS256 or EdDSA. The private license’s owner key was derived from the passkey’s PRF output with HKDF-SHA-256 (Ed25519). Being retired for customers’ licenses; staff licenses keep their passkeys (section 5). | Built — stage 1, being retired |
| Stage 1’s encrypted copy (the vault) | AES-256-GCM. The key is HKDF-SHA-256 of the passkey’s PRF output on a second, separate input. The current design has no vault: the Keychain holds the license, and an encrypted owner backup file (a password you choose) is designed for Macs with iCloud Keychain off. | Built — stage 1, being retired Designed the backup file |
| Revocation list, customer licenses | Ed25519, signed by a key the site holds. | Built |
| Staff licenses, the key list, the staff revocation list | WebAuthn approvals (ES256, a P-256 key) that chain up to one hardware key whose public half is built into the apps. | Built |
| What gets signed | Bytes with one rule: a version byte, then a fixed number of length-prefixed fields in a fixed order, and nothing after the last. No JSON is ever signed. A license’s message has seven fields; the Mac key is the seventh. | Built |
| Relay passes | Single-use, blind-signed passes — the same blind-signature core; a pass is 1 GB of Cody’s relay. A license has nothing to do with the relay, and passes never come from showing one: a purchase comes with starter passes, and a relay subscription hands them out to draw keys. The earlier note for this named Privacy Pass tokens (RFC 9576–9578); the format is not settled. | Built the format, the site’s signing and desk Designed the Mac app’s side |
1. Buying
The website takes the payment and hands the Mac app a one-time token; everything after that happens in the app. The first license from a purchase is signed in the open and recorded against the purchase. That is on purpose: a license signed blind cannot be found again by the site, so it could not be taken back. If the first license were private, a refund — or a charge on a stolen card — would leave a working license behind. So the first one is refundable, and the private one is prepared at the same moment and waits.
Figure 1. A purchase, step by step Built: the site’s side Designed: the Mac app, payment
The diagram scrolls sideways.
services/www/test/license-mac.test.mjs makes these calls the way the Mac app will). The left
lane is dashed because the Mac app does none of it yet, and it registers no link of its own today. Payment
through Stripe is not wired up; the only tokens are test ones, from a button on the admin site.What this proves
- One payment, one signature. The credit is spent in the same database statement that allows the signing; the same request sent again gets the same answer, and anything else on a spent credit is refused.
- The site can refund: it holds the refundable license’s id next to the purchase reference.
- Nothing of the private license reaches the site at purchase. The test captures every request of the claim, dumps every table and keeps every log line, and looks for the private license’s id, owner key and Mac key in all of it.
- The claim carries no cookie and names no Mac, room, device, invite or board identity; the keys in the refundable license are read and not stored.
What it does not
- A refundable license is matched to its payment: the site keeps its id beside the purchase reference (and reads the two public keys in it), and holds nothing about the person. Stripe holds the email and card behind that reference. The match is what makes a refund possible, and it ends when the license becomes private.
- The Mac app’s side is designed, not built: the keys in the Keychain and the Secure Enclave, the app making either license, the app opening from the link. In the test the Mac’s part is played by the test itself, with keys made in software.
- Stage 1, being retired: there the blinding ran in JavaScript that the site serves, and the owner was a website passkey. A site that served altered code at the moment of purchase could record what the browser made, and a page on its domain could ask the passkey for the owner key. Nothing let a buyer check the code they were served. The Mac app’s code is signed with a key the website does not hold and is checked by macOS before it runs.
- Stage 1’s vault, being retired with it: its row keeps the passkey’s public key — a stable handle — and the first write to a row is not authenticated: someone who knows a credential id could occupy the row first (16 KB and 20 writes an hour per address bound it).
Figure 2. What “signed blind” means Built Designed: the Mac app doing it
The diagram scrolls sideways.
What this proves
- By content, a private license cannot be matched to the request that produced it. The blinded number is independent of the license, and so are the two things the site keeps from a conversion (a hash of the request, the blind signature).
- Checking the result needs nothing special: it is an ordinary RSA-PSS signature.
- After a blind issuance the test dumps every table and looks for the license’s id, its owner key and the credential id. None is there.
What it does not
- That nobody can forge. That rests on an assumption (RSA one-more-inversion, RFC 9474 §7): from n signatures nobody can make n + 1. So every signature has to be a paid one — the single-statement spend, one way of signing per key, and a count of signatures per key against credits spent.
- Anything about timing or network addresses. See section 7.
- Anything about who holds the private key. Whoever has it can sign as many licenses as they like. See section 6.
2. Going private automatically
Privacy that has to be asked for is not much privacy, so the exchange is the default. The order for it is signed by the refundable license’s owner key when the license is made, under the same Touch ID; after the hold nobody has to approve anything again. “Keep it refundable” is a choice for whoever wants it: the order is simply not sent.
Figure 3. From refundable to private, and the keys of each Built: the site’s side Designed: the Mac app’s part
The diagram scrolls sideways.
services/www/test/license-mac.test.mjs: a license that carries an Ed25519 owner key and a Mac key,
the site converting on an order that owner key signed, and the search showing that the private license’s keys
reach the site in no request. Designed: all of the Mac app’s part — making the
four keys, signing the order, sending it by itself at a random moment within three days of the date, unblinding
the answer, one notice. Its Swift code is being written.What this proves
- The order cannot be reused for anything else. What the owner key signed is a hash of the refundable id, a hash of the blinded request, the not-before date and the key id; a changed date, another blinded request or another key’s signature is refused.
- The hold is the site’s to enforce: it refuses before the later of the order’s date and first issue + hold. Raising the hold later delays an order; it does not break it.
- The two licenses share no owner key, no Mac key and no id, and neither Mac key is the Mac’s identity key — checked on every captured request, every table and every log line.
What it does not
- The site knows that a given refundable license was converted, and when. The request comes from some address; the site stores none (rate limits use a keyed, daily-changing hash), but Cloudflare’s edge sees requests. Designed against the timing: the app sends the order at a random moment within three days, on a fresh connection with nothing else in the request.
- That the keys are where the design puts them. The site sees public halves; it cannot tell a key in a Keychain or a Secure Enclave from any other.
- Stage 1 only: one passkey gives one derived key, so a re-issued private license carries the same owner key as the one it replaces. The site never asked for that — a re-issue with a new owner key and a new Mac key is accepted, and tested — and the Mac app is designed to use new ones.
- A Mac that never goes online keeps its refundable license. A card dispute after the conversion leaves the license alive — accepted.
- An order names the signing key it was blinded for. After a key rotation the old key has to stay able to sign conversions, or a new order has to be made for the current key.
3. Checking a license offline
The Mac app, the headset app and the web client are meant to run the same check, from what is already on the device. The JavaScript one, for the web client, reads the current format and is held to a file of shared test vectors. The Swift one, for the Mac and headset apps, was built for stage 1’s format and is being brought to the current one.
Figure 4. The check, with no network Built: in the web client Designed: Swift, acting on the result
The diagram scrolls sideways.
services/www/test/license-mac.test.mjs; services/app/test/license-show.test.mjs for
the client itself): it keeps the result, logs one line without the license’s id, and changes nothing on
screen. The Swift reader for the current format, the Mac answering, the headset checking, what an app does
with the result, and the trial check are design.What this proves
- No network is involved: the answer follows from three things on the device.
- A license means what its signing key says. A test license that calls itself “everything-forever.enterprise” is a Mac license; a license under a test key is a test license whatever it says.
- The owner is no part of validity. Only the site’s owner actions look at the owner key.
- A license is accepted only from the Mac that holds its Mac key. The answer is checked against the key inside the license, the Mac identity key the client pinned when it paired, and the client’s own fresh challenge — so an answer from another key, or one relayed from another Mac, fails.
What it does not
- That the Mac key is in the Mac’s hardware. Nothing lets a client tell a Secure Enclave key from a software one; where the key is in software, a copy of the license together with its key passes this check (section 8).
- That anything answers. No Mac app answers the challenge yet, so today the web client records “no answer”; and the Swift reader has not followed the current format, so the two readers no longer agree on one set of vectors.
- That a revoke has arrived. A device knows the last list it saw; an offline Mac hears late, and a device that never saw a revocation can be handed an older, validly signed list.
- That the check runs. An app with the check patched out runs without a license. The code is not obfuscated, and this cannot be prevented.
4. Revoke, move, and the two lists
A license is made for one Mac. To replace it, or to move it to another Mac, its owner re-issues it: the old id goes on a list every device checks, and a new license is signed blind in its place. The proof of ownership is checked against the key inside the license itself, so the site does not need to know who the owner is.
Figure 5. The owner replaces or moves a license; the two revocation lists Built: the site’s side Designed: the Mac app’s side
The diagram scrolls sideways.
services/www/test/license-mac.test.mjs): the revoke,
the one credit, and a re-issue with a new owner key and a new Mac key, which the site does not compare with
the old ones. The Mac app’s two steps are designed. As designed, owner actions happen only on the owner’s
Macs, never in a browser — stage 1’s web page for them, with a website passkey, is built and being retired.
Bottom: two lists with two different signers. The site signs the customer list because conversions and
owners’ revokes add ids when nobody is at a hardware key.What this proves
- Through the site’s API, only the holder of the owner key can revoke a private license. Staff cannot: they can cancel a license only while it is still refundable, their revoke looks up refundable licenses, and a private one has no row. No staff power over private licenses exists or is planned.
- One revoke mints exactly one credit, in the same batch. A second revoke of the same id fails and mints nothing.
- The site cannot revoke a staff license, and cannot take a staff revocation back.
What it does not
- “Only the owner can revoke” is a statement about the site’s API and its staff. The customer list is signed with a key the site holds: whoever controls that key can list any license id they have seen, or un-revoke one.
- To revoke or move a private license its owner shows it to the site, which then sees its id and the two public keys in it; it keeps the id, on the revocation list, and neither key. The call carries no cookie and names no Mac or room, and a replacement with a new owner key and a new Mac key is in no request and no table: the site knows that the revoked license was replaced, and cannot tell what it became (tested). Stage 1 only: there the replacement carries the same owner key, so the two can be tied to each other, though not to a purchase.
- Stage 1 only: after a re-issue the page replaces the vault copy, seconds later and from the same address. The two requests share no value, but the timing is a guess at which passkey — and so which purchase — the license belongs to. The current design has no vault.
- A revoked license keeps passing on a device until that device gets a newer list. After a move, the old Mac’s copy works until the list arrives.
- Whoever holds a license and its owner key can move it — that is what the owner key is for. On the owner’s Mac the key is designed to come out of the Keychain only after Touch ID or the Mac’s password.
Another Mac of yours Designed
It sees the owner keys through iCloud Keychain and offers two things: move the license to this Mac — a re-issue; the other Mac’s copy stops when it next sees the list — or buy a license for this Mac. A second Mac is a second license; moving is free.
iCloud Keychain off Designed
The owner keys live on that Mac only. The app’s License page says so and offers an encrypted owner backup file, locked with a password you choose. Share License… saves the license itself; that file works nowhere by itself.
Lost the Mac, and no copy of the owner key Later
The license was bound to that Mac’s hardware, and nothing is left that can move it. There is no automatic way back, on purpose: re-issuing from a receipt could leave the old license alive. It would be handled by hand.
Stage 1: lost the file, kept the passkey Built
Being retired. Sign in with the passkey; the site returns the encrypted copy and the browser opens it. This needed PRF: without it there was no vault copy.
5. Staff powers are licenses too
Admin rights are not rows in a table the website could edit. Each one is a role license. It is approved through a short chain that ends at a hardware security key held by the business owner, and it is usable only together with its holder’s own passkey. Role licenses are not blind: they are meant to be known and revocable.
Figure 6. The chain behind a staff power, and who can cancel a refundable license Built Designed: the dashboard screens
The diagram scrolls sideways.
What this proves
- A taken-over website cannot make an admin: every role license chains to a hardware key whose private half is on no server.
- A copied role license does nothing by itself, and the admin token alone authorizes nothing: each privileged request needs the license and a fresh passkey approval bound to that action and its target.
- Staff can cancel a license only while it is still refundable, and a billing admin cannot do it alone: an owner approves it. Once a license is private, only its owner can revoke it: no staff power over private licenses exists or is planned.
What it does not
- That an owner’s key is safe. Whoever holds an owner’s key and can unlock it has an owner’s powers. Another owner can revoke that owner license; if the anchor itself is lost with no second key enrolled, the apps need an update with a new anchor.
- No anchor is enrolled today: the built-in list is empty until the first one is made.
- The audit log is a table in the site’s database, not a signed record; the reason text in it is not covered by the approval; and a list’s date is its signer’s word.
- The site itself goes by its own database for staff revocations. Whoever can roll that database back can make the site forget one — the apps still refuse.
6. Signing keys
What a license means comes from the key that signed it, so the keys are the thing to protect. There is one key per product, per mode (live or test) and per quarter. Each key signs one way only: a blind key never signs anything it has read, and the others never sign blind.
Figure 7. Quarterly keys, how a key becomes trusted, and what happens if one leaks Built Designed: the signer, re-claim, alarms
The diagram scrolls sideways.
What this proves
- The website cannot make the apps trust a new signing key. Tested: a row written straight into the table is served, and both readers ignore it.
- Rotating keys needs no app update and breaks no existing license.
- A leaked key can be shut off without an app update, and the damage is one quarter’s licenses.
What it does not
- As built today, private keys would be Worker secrets created on a developer’s machine. Anyone who can read those secrets, or deploy code to the site, can sign. The signer Worker that would generate keys inside itself is not built.
- Even with the signer, code deployed to it could read its storage. What is planned against that: a tiny surface, its own deploy token, two-factor on the account, and the count above.
- Distrust cannot tell forged licenses from genuine ones under the same key — they are blind — so genuine holders lose theirs until they re-claim, and re-claim is not built.
- Offline devices hear of a distrust late. The apps’ saved copy of the key list is not built.
7. What the site can connect
“The site” here means the website’s server as built, plus anyone who controls it and chooses to log more than the code does. “By content” means from values stored or sent; timing and network addresses are separate rows because they are a different kind of evidence.
| Two things | Can the site connect them? | Why | Status |
|---|---|---|---|
| A payment ↔ its refundable license | Yes, on purpose | The license id is recorded with the purchase reference so the purchase can be refunded. Stripe holds the email and card behind that reference; the site reads neither. | Built |
| A refundable license ↔ the fact and time it went private | Yes | The site performs the conversion and marks the purchase. | Built |
| A refundable license ↔ the private license it became, by content | No | Signed blind; a different id, a different owner key, a different Mac key. What the site keeps from the conversion is independent of the final license. Tested: the private license’s id and keys are in no request of the claim or the conversion, in no table and in no log line. | Built |
| A payment ↔ a private license, by content | No | Follows from the row above: a private license has no row in any table. Staff can cancel a license only while it is still refundable; a private one only its owner can revoke, and no staff power over private licenses exists or is planned. | Built |
| The same two, by timing and address | A guess, for a site that logs | The conversion arrives from the Mac’s address, and a private license shown to the site later from the same address is a guess anyone could make. The site’s code stores no address; Cloudflare’s edge sees every request. Designed to leave less to guess from: the app converts at a random moment within three days, on a fresh connection with nothing else in the request, and a private license is shown to the site only for an owner action or an update check. | Built — open weakness Designed the random moment |
| A private license ↔ its replacement after a re-issue or a move | No, by content, when the keys are new. Stage 1’s page: yes, if shown both | The site does not ask that a replacement keep the old keys: one with a new id, a new owner key and a new Mac key is in no request and no table (tested), and the Mac app is designed to make it that way. Stage 1’s web page re-derived the same owner key for the replacement. | Built the site’s side Designed the Mac app Built — stage 1’s page, being retired |
| A license ↔ a Mac | No, at the site | A license names a Mac key, but that key belongs to this one license: the refundable and the private license get two unrelated ones, and neither is the identity key that rooms and devices know the Mac by. The proof that a Mac holds its license is asked for by a headset or browser over the direct channel, never through a call to the site. Tested: no stored row and no log line holds a license id beside an address, a room, a device, an invite or a board identity, and the Mac’s identity key is never sent. | Built the site, the web client Designed the Mac app, the headset |
| A private license ↔ its update checks | As designed: yes | A licensed Mac would show its license when it checks for an update, with an install number — a random value made on that install, mixed with the license id so it means nothing anywhere else. Per license id the site would keep the first install number and a count of different ones seen in 90 days: the id is seen at an address at that moment, and the address is not stored. It is not linkable to the buyer, a room, a device or use of the relay. This is the one routine call that carries a license; it exists to notice copies (section 8). | Designed |
| A license ↔ use of the relay | As designed: no | A license has nothing to do with the relay. The relay takes single-use, blind-signed passes, and passes never come from showing a license: a purchase comes with starter passes, signed blind in the claim against the same one-time token, and a relay subscription hands them out to draw keys. The site would know that a purchase got starter passes, and could not recognize one when it is spent. | Designed |
| A relay subscription ↔ a license | As designed: no | A subscription has draw keys, one for each Mac allowed to use it, and no license ids. The site would see a Stripe customer, a count of Macs and how many passes each key drew — never a license, a room or a device. | Designed |
| One relay session ↔ another | As designed: yes within one relay tab, no beyond it | Passes are paid into a tab — a random id only that Mac knows, dropped when it is empty or 30 days old. Use is linkable within a tab, and not to the license, the subscription or the next tab. Addresses and timing remain what they are. | Designed |
| A license ↔ a board identity (points, votes) | No | A license reaches the site in three calls only — the conversion, an owner action, and as designed the update check — each with no cookie and no room. Tested for the first two: the rows that name a person hold no license id, and the rows that hold a license id name nobody. Starter points would come as a separate blind-signed voucher, redeemable into any identity. | Built the two calls Designed the update check, vouchers |
| A trial ↔ a Mac | As designed: yes | A trial ticket is signed in the open and names the Mac’s identity key. One per Mac is kept by Apple’s DeviceCheck (a per-device flag at Apple), with a hash of the hardware id as the fallback. | Designed |
| A role license ↔ a staff member | Yes, on purpose | Role licenses are not blind. The label, the roles and the holder’s passkey are in the signed message, and every action is logged under the role license’s id. | Built |
| Stage 1 only: a refundable license ↔ its vault copy | Yes | The vault row holds the passkey’s public key, which is also inside stage 1’s refundable license. The current design has no vault. | Built — stage 1, being retired |
| Stage 1 only: a private license ↔ a passkey, at re-issue | A guess, by timing | The vault copy is rewritten seconds after the revoke, from the same address. No value is shared between the two requests. The vault write can be skipped. | Built — stage 1, being retired |
What the site keeps in general — devices, the board, payments — is on What Cody stores.
8. Who could attack it, and what they get
| Attacker | What they get | What stops or limits it | Status |
|---|---|---|---|
| Someone with a stolen license file, a cloned disk, or a leaked owner key | A license whose signature checks out anywhere. | A client accepts a license only together with a fresh challenge signed by the Mac key the license names. Tested in the web client: not from another key, not from the Mac’s identity key, not for another Mac’s connection. As designed that key’s private half is made inside one Mac’s Secure Enclave and cannot leave it, so a file, a disk image or an owner key does not contain it and the license runs on no other Mac. No Mac app answers the challenge yet, and the headset’s check is not built. | Built the proof, the web client’s check Designed the Mac’s key and answer, the headset |
| A shared license (posted in public) | The same file, in many hands. | It answers a challenge on the one Mac it was made for. A second Mac is a second license; moving to a new Mac is the owner’s re-issue, and the old license goes on the revocation list. The relay is no part of a license, so sharing one shares no relay use. | Built the proof, the re-issue at the site Designed the Mac app |
| A Mac key that is not in the Mac’s hardware | A Mac without a Secure Enclave keeps its Mac key in the Keychain instead, and nothing lets the site or a client tell a hardware key from a software one. A license whose key is in software can be copied together with its key, and every copy passes an unmodified client’s check. | This is a limit, and it cannot be prevented offline. Designed against it: a licensed Mac shows its license when it checks for an update, and the site counts, per license id, how many different installs it has seen in 90 days. The first install keeps getting updates from that check; any other is told the license is in use on another Mac, with the choice to move it there (which takes the owner key) or buy one. That takes automatic updates away from casual copies and shows that a license is being passed around. It does not stop a determined copier: the update file is the same for everyone, and a patched app can skip the check. It gives nobody new powers: a private license is still revoked only by its owner, and no staff power over private licenses exists or is planned. | Designed |
| A patched app | The Mac app running with the license check removed. | This cannot be prevented, and the code is not obfuscated. The answer is the check in the official headset and web clients, which a patched Mac app cannot skip for them — and the relay costs passes whichever app asks. | Built the web client’s check Designed the headset’s, the apps acting on it, passes |
| A leaked signing key (blind) | Any number of licenses nobody can tell from real ones. | An owner’s distrust entry ends everything under that key; quarterly keys bound it to one quarter; signatures per key are counted against credits spent. Genuine holders would need to re-claim. | Built distrust, counters Designed alarms, re-claim |
| A leaked refundable signing key | Refundable-kind licenses the site has no row for, so staff cannot find them to revoke. | Distrust, as above. | Built |
| A leaked list key | The power to un-revoke a customer’s license (a shorter list with a higher version), or to list any id they know. | Customer licenses only: staff licenses are on a list an owner signs. A device refuses a list older than the one it keeps. | Built |
| Someone who takes over the website | The database, the Worker’s secrets — today that includes every signing key — and the pages the site serves. | They cannot: find a private license (none is stored), connect one to a purchase by content, make an admin, add a signing key the apps accept, or take back a staff revocation. They can: sign licenses until the key is distrusted, change the customer revocation list, and log addresses and timing from then on. As designed they cannot touch how a license is made: that happens in the Mac app, whose code the website does not sign. The page that hands the token to the app makes no license and sends the site nothing. | Built Designed the license made in the Mac app; keys out of the site’s reach |
| The same, against stage 1’s web path | The page that made licenses in the buyer’s browser, and the domain the owner passkey belongs to. | Nothing limited it: altered code could record what the browser made, and a page on the site’s domain can always ask a website passkey for its key. This is why that path is being retired and is linked from nowhere. | Built — stage 1, being retired |
| A dishonest admin | A billing role: the power to ask for the revoke of a refundable license. | The request waits for an owner’s approval and lapses after 7 days. Staff can cancel a license only while it is still refundable; once it is private only its owner can revoke it, and no staff power over private licenses exists or is planned. Every act is an audit row. A daily cap on revokes is designed. | Built Designed cap, screens |
| Someone holding only the admin token, or a copied role license | A request that reaches the admin API. | Nothing is authorized without a role license and a fresh approval from its holder’s passkey. | Built |
| A buyer with a stolen card | A refundable license. | During the hold the license can be revoked and the charge refunded. After the conversion there is nothing to revoke; a dispute then leaves the license alive. | Built hold, revoke Designed Stripe side |
| Trial farming | Repeated 14-day trials. | One trial per Mac through Apple’s DeviceCheck, which survives reinstall and erase; where that is unavailable (older Intel Macs, virtual machines), a hash of the hardware id instead. A daily cap, and a switch to turn trials off or require a card. A wound-back clock is caught by a latest-time-seen mark. | Designed |
| An owner whose Mac is lost or dead | Not an attack. With iCloud Keychain, or the owner backup file, the owner key is still theirs and the license can be moved to another Mac. | With neither, nothing is left that can move the license. No automatic recovery, on purpose. By hand, if it happens. | Designed the move Later by hand |
| Stage 1 only: someone who knows a passkey’s credential id | They can write the vault row for it before its owner does. | 16 KB per row and 20 writes an hour per address. The owner still holds the license file. The current design has no vault. | Built — stage 1, being retired |
9. Test evidence
All tests use throwaway keys made in the test and a software passkey that produces real WebAuthn data. The counts are from a run on October 1, 2026. None of them runs the Mac app or the headset: where a test needs a Mac, the test plays it, with keys made in software.
| Test | What it pins | Checks |
|---|---|---|
services/www/test/license.test.mjs | The byte format; blind issuance end to end (blind, sign, unblind, verify offline); one signature per credit; a license means what its key says; a refundable license is recorded, a private one leaves no trace in any table; rate limits. | 60 |
services/www/test/license-owner.test.mjs | Revoke and re-issue for both kinds of owner key; the conversion order and its hold; the staff refund revoke; the vault; the site-signed revocation list. | 101 |
services/www/test/license-browser.test.mjs | The buyer’s browser code itself, run against the site. It captures every request the page makes and dumps every table, then searches all of it for the private license’s owner key — as written and inside anything base64url or hex, three levels deep — with the passkey’s own key as the control that the search finds what is there. With PRF and without. | 57 |
services/www/test/license-roles.test.mjs | Role chains; the admin token alone revokes nothing; a role license is nothing without its passkey; the two-step revoke; audit rows; owners make owners, three links at most; the owner-signed role list; the site-signed list has no say over a role; the site cannot take a role revocation back. | 79 |
services/www/test/license-keys.test.mjs | Signatures counted per key; a key joins the list only with an owner’s approval; a distrusted key’s licenses all fail; a revoked owner’s entries fall with it. | 38 |
services/www/test/license-mac.test.mjs | The Mac app’s side of a license, as plain requests with no cookie: the claim, the order approved by an Ed25519 owner key and its hold, revoke and re-issue as a move to another Mac with new keys, the page that hands the token to the app, a client’s check of the Mac’s answer. And what the site must never connect: every request is captured, every table dumped and every log line kept, then searched — as written and inside anything base64url or hex, three levels deep — for the private license’s id and keys, and for a license id beside an address, a room, a device, an invite or a board identity. | 64 |
services/app/test/license-show.test.mjs | The web client asking a Mac for its license: a fresh challenge out, the answer checked offline against the pinned identity key, the result kept and logged in one line that never holds the license’s id. | passes; not counted here |
tools/tests/license-vectors.json | The shared vectors, public halves only: 18 licenses good and bad, 9 site-signed lists, 15 role chains, 18 role lists, a conversion order with the private license it becomes, the key list, and the derived owner key (pinned, because changing the derivation would lock every owner out). | — |
tools/tests/license.mjs | The JavaScript reader against those vectors. | 155 |
tools/tests/unit-license.swift | The Swift reader (the Mac app’s and the headset’s) against the shared vectors, including unblinding. Written for stage 1’s format; it is being brought to the current one, with the Mac key, and until then does not pass against the current vectors. | in progress |
| A real browser, driven by hand | The /license/ page on a local server in a headless Chrome with a virtual authenticator, twice — with PRF and without — and the page that makes role licenses, once. Not part of the automated run. Not tried in Safari. | by hand |
What the tests cannot show: that a deployed site behaves like the tested code, how real authenticators and Safari behave, and anything about parts tagged Designed or Later.
10. Not built yet
- Designed Buying. Stripe Checkout for a license, the webhook that grants the signing credit, starter points, refunds on the Stripe side.
- Designed The Mac app making and holding the license. The owner keys in the Keychain behind Touch ID, the Mac keys in the Secure Enclave, opening from the claim link, making both licenses and signing the conversion order, swapping to the private license by itself after the hold, re-issuing and moving a license to another Mac, answering a client’s challenge, Share License… (a backup, and the way to hand a license to the Mac it is moving to), the encrypted owner backup file. This is being written now; none of it is tagged Built until it has tests. The site’s side of every one of these calls is built.
- Designed The headset checking a license, and the Swift reader reading the current format: it was built for stage 1’s and has not followed yet.
- Designed The update check that notices copies. The install number, the count per license id, the notice on a second install.
- Designed Relay passes. Starter passes with every purchase, a subscription’s draw keys, relay tabs. None of it takes a license.
- Designed Real keys. No signing key, list key or anchor has been made, so no site can issue a license today.
- Designed The signer Worker. Keys generated inside a separate Worker that no person can read. Today there is only its interface, and keys would be Worker secrets.
- Designed The apps acting on a license. Today the web client checks a Mac’s license and only records the result. The limited mode without a license, and the apps’ saved copies of the key list, are not built.
- Designed Trials. The 14-day ticket, one per Mac, the switch and the daily cap.
- Designed Gifts and points. A claim link that can be sent on to someone else; points vouchers.
- Designed Watching. The signatures-equal-credits alarm, the other alarms, the signer pausing itself, the weekly digest.
- Designed Dashboard screens. Pending revokes, the audit log, keys awaiting approval, revoking a role license, the daily cap on revokes.
- Designed Re-claim after a distrust. One new credit per purchase of the distrusted quarter.
- Later A compact revocation list for when it grows past thousands of ids; recovery for an owner key lost with its Mac; and how a company keeps control of licenses it buys for its people — the earlier design had the company approve each Mac, and that step no longer exists.
Going the other way: stage 1’s web page for making a license, its website passkey as owner and its vault are built and tested, and are being retired. They stay in the code, linked from nowhere, until the Mac app’s path has been tried; then they go.