Files
dashcaddy-license-server/README.md
T

4.0 KiB

DashCaddy License Server

Production billing and license fulfillment for purchases made on dashcaddy.net.

Requires Node.js 22.5 or newer for the built-in node:sqlite transactional store.

What it does

  • Creates Stripe Checkout sessions for one-time purchases and auto-renewing subscriptions.
  • Verifies signed Stripe webhooks with durable event idempotency.
  • Creates one stable DashCaddy license key per customer and extends that key on later purchases or renewals.
  • Tracks one-time and subscription paid-through components separately, so subscription failure cannot erase valid one-time access.
  • Emails the exact key accepted by the validation API and tracks each renewal email per Stripe invoice.
  • Keeps subscriptions active through their paid period; failed renewals receive a seven-day grace period.
  • Supports one-machine activation and deactivation.
  • Migrates the previous JSON store into a transactional SQLite database on first startup.

Plans

Plan One-time / renewal amount Subscription interval
premium_30d $20 1 month
premium_90d $50 3 months
premium_180d $70 6 months
premium_365d $99 1 year

Stripe remains the billing source of truth. SQLite is the entitlement and fulfillment source of truth.

Server-managed keys use DashCaddy's HMAC-compatible code format for initial activation, but renewed expiry is authoritative online because a stable signed code cannot encode changing renewal dates. The DashCaddy client refreshes server-managed entitlements from the license server and does not create a new activation through offline fallback when that server is configured.

Environment

PORT=3010
APP_BASE_URL=https://licenses.dashcaddy.net
DASHCADDY_WEBSITE_URL=https://dashcaddy.net
STRIPE_SECRET_KEY=sk_live_...
STRIPE_PUBLISHABLE_KEY=pk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
DASHCADDY_LICENSE_SECRET=64_hex_characters_shared_with_dashcaddy
DATA_DIR=./data
ADMIN_TOKEN=generate-a-long-random-token

SMTP_HOST=mail.sami-ahmed.net
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USERNAME=licenses@dashcaddy.net
SMTP_PASSWORD=...
SMTP_FROM=licenses@dashcaddy.net
# Keep certificate verification enabled in production.
SMTP_TLS_REJECT_UNAUTHORIZED=true

Public HTTP endpoints

  • GET /health
  • GET /api/public/config
  • GET /api/public/plans
  • POST /api/checkout/one-time
  • POST /api/checkout/subscription
  • GET /api/checkout/session/:sessionId
  • POST /api/stripe/webhook
  • POST /api/license/validate
  • POST /api/license/deactivate

GET /api/admin/debug/store requires Authorization: Bearer $ADMIN_TOKEN and is hidden with a 404 when no admin token is configured.

Checkout request

{
  "planCode": "premium_30d",
  "customerEmail": "buyer@example.com"
}

A successful checkout request returns a Stripe-hosted url and a sessionId. The website redirects to Stripe. After payment, Stripe calls the webhook, the license is created or extended, SMTP delivery is recorded, and the website polls /api/checkout/session/:sessionId to display the same key sent by email.

Safety properties

  • Checkout accepts only valid plan codes and email addresses.
  • Browser CORS is restricted to dashcaddy.net and www.dashcaddy.net.
  • Checkout creation is rate limited.
  • Webhook event IDs and payment intent IDs are idempotent.
  • Store changes use SQLite transactions and WAL durability.
  • Repeated checkout sessions are stored independently.
  • Admin customer/license data is not public.
  • SMTP certificate verification is enabled by default.

An email marked delivered means the configured SMTP provider accepted it; final inbox placement remains the receiving mail system's responsibility. The success page also displays the same valid key, so fulfillment does not depend on inbox delivery.

Test

npm test

The tests cover CORS, invalid checkout input, admin isolation, exact-key lookup and validation, payment idempotency, rate limiting, durable webhook claims, repeat checkout lookup, cancellation, and payment-grace expiry.