Fair-code licensing: offline Ed25519 verification + seat enforcement + check-in (v0.4 #24) #44
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/license"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Implements the enforcement model recorded on #24, with the production public key (M1) embedded.
Key format:
CAIRN1.<b64url(payload)>.<b64url(sig)>— payload{id, org, seats, issuedAt, expiresAt, keyId}, Ed25519-verified offline against the embedded public key (private key never enters this repo;license.Signexists for the server and tests only).Seat accounting (no DB): distinct authenticated usernames, persisted to
license.statePathJSON. Enforcement wraps the auth provider: known users and admins always pass; a new user is admitted only under the cap (50free tier, or the license's seat count when active). Existing users are never locked out; reads are never blocked.Check-in: monthly against
license.checkinUrl, only when >50 seats are in use (≤50 never phones home, key installed or not). Connectivity failure → daily retry, 7-day grace (surfaced in status), then the license stops counting until a check-in succeeds. Server 403 → revoked immediately. Payload is just{licenseId, seatsUsed}— no telemetry.API:
GET/PUT /api/v1/license(admin-gated) — status (org, cap, seats used, expiry, last check-in, grace deadline) and key installation (persists across restarts via the state file, so the config secret needn't change). Config blocklicense {key, checkinUrl, statePath}+CAIRN_LICENSE_KEY.Tests: parse/tamper/wrong-key, embedded-key parse, free-tier cap + admin bypass, license raises cap, expired-install rejection, grace-window expiry drops cap (existing over-cap user stays admitted), revocation, state persistence across restart.
UI (Settings → License, #43) follows in the next PR.