Skip to content

Move paid unlock from Gumroad to self-hosted Ko-fi licensing#7

Merged
peterdsp merged 1 commit into
mainfrom
feat/kofi-licensing
Jul 8, 2026
Merged

Move paid unlock from Gumroad to self-hosted Ko-fi licensing#7
peterdsp merged 1 commit into
mainfrom
feat/kofi-licensing

Conversation

@peterdsp

@peterdsp peterdsp commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Why

klipa's direct-download paywall verified license keys against Gumroad, but the app now sells on Ko-fi, which has no license-key API. Buyers coming from the site got keys the app couldn't validate. This switches klipa to the same self-hosted, email-based flow PromptBar already uses.

How

App (license.rs):

  • Activation reads the buyer's Ko-fi email from the clipboard, POSTs it to the license server's /activate, and verifies the returned Ed25519-signed license offline against an embedded public key. Validates product, email, and min_version; re-verifies every 14 days (refund handling) with offline grace.
  • Drops the Gumroad verify path + product-id build var. Ko-fi buy link and licenses.peterdsp.dev endpoint are now source defaults, overridable at build time.
  • Verification via ed25519-compact (tiny, dependency-light) + existing base64. The canonical signed message matches the Python signer byte-for-byte - a unit test using a real server-signed blob proves the cross-language match and rejects tampering / wrong email.

http.rs: replaces form-encoded post_form with JSON post_json.

Server: the shared multi-product license server (PromptBar/scripts/pi-license-server/) now signs both PromptBar and klipa from the one Ko-fi webhook, keyed by shop item. Deployed + validated on the Pi. scripts/pi-license-server/README.md documents klipa's slice.

Config/docs: release.yml drops KLIPA_GUMROAD_PRODUCT_ID (GitHub variable deleted; KLIPA_PURCHASE_URL repointed to Ko-fi); menu label, root README, welcome page, packaging README, and release-secrets runbook updated.

Testing

  • cargo test -p klipa-ui - 8 pass, incl. the real-signature verify/tamper test.
  • Builds clean on default, mas, mas weather, and no-default-features.
  • App Store build unaffected (license feature compiled out there).

klipa's direct-download paywall verified license keys against Gumroad,
but the app now sells on Ko-fi - which has no license-key API. Switch to
the same self-hosted, email-based flow already used by PromptBar.

App side (license.rs):
- Activation now takes the buyer's Ko-fi email from the clipboard, POSTs
  it to the license server's /activate, and verifies the returned
  Ed25519-signed license offline against an embedded public key. Checks
  product, email, and min_version. Re-verifies every 14 days to honour
  refunds, with offline grace on network failure.
- Drop the Gumroad verify call and product-id build var; add the license
  endpoint + purchase URL (Ko-fi) as source defaults, overridable at
  build time.
- Verification uses ed25519-compact (tiny, dependency-light) + base64.
  Canonical message matches the Python signer byte-for-byte; a test with
  a real server-signed blob proves it and rejects tampering.

http.rs: replace form-encoded post_form with JSON post_json for /activate.

Config/docs: release.yml drops KLIPA_GUMROAD_PRODUCT_ID; menu label,
README, welcome page, packaging README and release-secrets runbook
updated; add scripts/pi-license-server/README.md documenting the shared
multi-product server and klipa's keypair/env.

App Store build is unaffected: the license feature is compiled out there.
Copilot AI review requested due to automatic review settings July 8, 2026 09:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@peterdsp
peterdsp merged commit 268e3ed into main Jul 8, 2026
4 checks passed
@peterdsp
peterdsp deleted the feat/kofi-licensing branch July 8, 2026 09:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants