{"_id":"@aikdna/kdna-activation-server","_rev":"6-4de23c6a5f6b55c8779167f9a874036c","name":"@aikdna/kdna-activation-server","dist-tags":{"latest":"0.2.1"},"versions":{"0.1.0":{"name":"@aikdna/kdna-activation-server","version":"0.1.0","keywords":["kdna","kdna-activation-server","license","entitlement","self-hosted","creator-license-management"],"license":"Apache-2.0","_id":"@aikdna/kdna-activation-server@0.1.0","maintainers":[{"name":"code2mp4","email":"hi@code2mp4.com"}],"homepage":"https://github.com/aikdna/kdna-activation-server","bugs":{"url":"https://github.com/aikdna/kdna-activation-server/issues"},"bin":{"kdna-activation-server":"bin/kdna-activation-server.js"},"dist":{"shasum":"0a08bcfae03f34d408397e27bf682ed4b7bf0974","tarball":"https://registry.npmjs.org/@aikdna/kdna-activation-server/-/kdna-activation-server-0.1.0.tgz","fileCount":9,"integrity":"sha512-R9J/pSoXp6CXTir0jWJ3TO4C0kGKLrA/fh+1bd71gtvG0KViL5ri1cxj6E14KQrgkJbIP3WKIB5np5pYDZQx8A==","signatures":[{"sig":"MEUCIEGlKAT8/wsMXy1aZbDDoz0MTjMPw2mXWmzuICtJCGh+AiEA6//3nndW1eB2JZD+TtdnFvpoVk2A+byE2VpidfbLtvo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32471},"main":"src/index.js","type":"commonjs","engines":{"node":">=18"},"gitHead":"e5c03b6fbc09c098f10a6af7a1f4d1fe3f6a3c7c","scripts":{"test":"node --test tests/","start":"node bin/kdna-activation-server.js"},"_npmUser":{"name":"code2mp4","email":"hi@code2mp4.com"},"repository":{"url":"git+https://github.com/aikdna/kdna-activation-server.git","type":"git"},"_npmVersion":"10.9.8","description":"KDNA activation server — self-hostable HTTP server for license activation, sync, revocation. Implements specs/kdna-entitlement-api.md and the self-hosting invariant from docs/REMOTE_MODE.md (Story 24).","directories":{},"_nodeVersion":"22.22.3","dependencies":{},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/kdna-activation-server_0.1.0_1782670183451_0.4311744259497048","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@aikdna/kdna-activation-server","version":"0.1.2","keywords":["kdna","kdna-activation-server","license","entitlement","self-hosted","creator-license-management"],"license":"Apache-2.0","_id":"@aikdna/kdna-activation-server@0.1.2","maintainers":[{"name":"code2mp4","email":"hi@code2mp4.com"}],"homepage":"https://github.com/aikdna/kdna-activation-server","bugs":{"url":"https://github.com/aikdna/kdna-activation-server/issues"},"bin":{"kdna-activation-server":"bin/kdna-activation-server.js"},"dist":{"shasum":"eecc3ed49534bd567a3fbe147cfd299359f63031","tarball":"https://registry.npmjs.org/@aikdna/kdna-activation-server/-/kdna-activation-server-0.1.2.tgz","fileCount":10,"integrity":"sha512-KKouxrT1JWNoI4cI+VKYoZEbUo7AfLBkapnNnsnWPYhVtsuoEFhNEQlHW1Mgl5eUGEGwSqbfCiwVSDAc3pylTw==","signatures":[{"sig":"MEQCIAsj7zM3Aia41E8f5InHsqLN+ms3yGPzTF/1whtMBuoVAiBNOVu8OLq+CAHsUFUc5mf5Dm12bvC31RutV0p8CdU2gA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aikdna%2fkdna-activation-server@0.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":34086},"main":"src/index.js","type":"commonjs","engines":{"node":">=18"},"gitHead":"9ba3c71b50dc282f24f1fb455a0e79019d36458f","scripts":{"test":"node --test tests/*.test.js","start":"node bin/kdna-activation-server.js","prepublishOnly":"npm test"},"_npmUser":{"name":"code2mp4","email":"hi@code2mp4.com"},"repository":{"url":"git+https://github.com/aikdna/kdna-activation-server.git","type":"git"},"_npmVersion":"10.9.8","description":"KDNA activation server — self-hostable HTTP server for license activation, sync, revocation. Implements specs/kdna-entitlement-api.md and the self-hosting invariant from docs/REMOTE_MODE.md (Story 24).","directories":{},"_nodeVersion":"22.23.1","dependencies":{},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/kdna-activation-server_0.1.2_1783932870991_0.1816518000499705","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@aikdna/kdna-activation-server","version":"0.2.0","keywords":["kdna","kdna-activation-server","license","entitlement","self-hosted","creator-license-management"],"license":"Apache-2.0","_id":"@aikdna/kdna-activation-server@0.2.0","maintainers":[{"name":"code2mp4","email":"hi@code2mp4.com"}],"homepage":"https://github.com/aikdna/kdna-activation-server","bugs":{"url":"https://github.com/aikdna/kdna-activation-server/issues"},"bin":{"kdna-activation-server":"bin/kdna-activation-server.js"},"dist":{"shasum":"388b79d65790c6d29083c9392dba0e9786975575","tarball":"https://registry.npmjs.org/@aikdna/kdna-activation-server/-/kdna-activation-server-0.2.0.tgz","fileCount":11,"integrity":"sha512-OnfgWeKYPKt3Fr764jTbqtdVP7XubjkgtuDavGGKtZK2vqDSCl3y/mMFDDcSUEbCxOQuLM4QSa/sutdbpP5Krg==","signatures":[{"sig":"MEUCIBN/KG7hqDEwaSGcrOLDNt346J6XtPy6F9h1Na4dKSE/AiEA/acSeeLCbWH/xL4Ki+hw4me2j2nIdo44+21X8ZEo8lI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aikdna%2fkdna-activation-server@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":60885},"main":"src/index.js","type":"commonjs","engines":{"node":">=18"},"gitHead":"bb75f114fbd0969a176671e12df3b003186228da","scripts":{"test":"node scripts/check-public-surface.js && node scripts/check-protocol-names.js && node --test tests/*.test.js","start":"node bin/kdna-activation-server.js","prepublishOnly":"npm test","check:protocol-names":"node scripts/check-protocol-names.js","check:public-surface":"node scripts/check-public-surface.js"},"_npmUser":{"name":"code2mp4","email":"hi@code2mp4.com"},"repository":{"url":"git+https://github.com/aikdna/kdna-activation-server.git","type":"git"},"_npmVersion":"10.9.8","description":"KDNA activation server — self-hostable HTTP server for license activation, sync, revocation. Implements specs/kdna-entitlement-api.md and the self-hosting invariant from docs/REMOTE_MODE.md (Story 24).","directories":{},"_nodeVersion":"22.23.1","dependencies":{"@aikdna/kdna-core":"0.20.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/kdna-activation-server_0.2.0_1784360252829_0.29478124537137207","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@aikdna/kdna-activation-server","version":"0.2.1","description":"Self-hostable KDNA entitlement service for license activation, synchronization, revocation, and signed status records.","type":"commonjs","main":"src/index.js","bin":{"kdna-activation-server":"bin/kdna-activation-server.js"},"scripts":{"start":"node bin/kdna-activation-server.js","check:public-surface":"node scripts/check-public-surface.js","check:protocol-names":"node scripts/check-protocol-names.js","lint":"node scripts/check-syntax.js","test":"node scripts/check-public-surface.js && node scripts/check-protocol-names.js && node --test tests/*.test.js","prepublishOnly":"npm test"},"engines":{"node":">=18"},"dependencies":{"@aikdna/kdna-core":"0.21.0"},"license":"Apache-2.0","repository":{"type":"git","url":"git+https://github.com/aikdna/kdna-activation-server.git"},"bugs":{"url":"https://github.com/aikdna/kdna-activation-server/issues"},"homepage":"https://github.com/aikdna/kdna-activation-server","keywords":["kdna","kdna-activation-server","license","entitlement","self-hosted","creator-license-management"],"_id":"@aikdna/kdna-activation-server@0.2.1","gitHead":"6e9d6e6384678d64be806c5206a463638e4ecac1","_nodeVersion":"22.23.1","_npmVersion":"10.9.8","dist":{"integrity":"sha512-q+DygfvtgFKDI9iZKuXyrCV2X4wF/iEgfmeHaRQNOKUKVTpe787baFpjQr2WNjDs7Kc8PRsBJpa54+3v1II/sg==","shasum":"5cc14fbd1be7ee88e1b571b30ea8ea53e834cb1e","tarball":"https://registry.npmjs.org/@aikdna/kdna-activation-server/-/kdna-activation-server-0.2.1.tgz","fileCount":12,"unpackedSize":89907,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aikdna%2fkdna-activation-server@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDrRiN7o86meyFJAuIIayyg2nkEiAJs87iw4wbkCDyQjQIgD8KXxcW4eaHcGrpDY+i0xYJre2qIf41fKZ2CZ13MInk="}]},"_npmUser":{"name":"code2mp4","email":"hi@code2mp4.com"},"directories":{},"maintainers":[{"name":"code2mp4","email":"hi@code2mp4.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/kdna-activation-server_0.2.1_1786238404411_0.6109768500104709"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-28T18:09:43.314Z","modified":"2026-08-09T01:20:04.897Z","0.1.0":"2026-06-28T18:09:43.572Z","0.1.2":"2026-07-13T08:54:31.114Z","0.2.0":"2026-07-18T07:37:32.965Z","0.2.1":"2026-08-09T01:20:04.558Z"},"bugs":{"url":"https://github.com/aikdna/kdna-activation-server/issues"},"license":"Apache-2.0","homepage":"https://github.com/aikdna/kdna-activation-server","keywords":["kdna","kdna-activation-server","license","entitlement","self-hosted","creator-license-management"],"repository":{"type":"git","url":"git+https://github.com/aikdna/kdna-activation-server.git"},"description":"Self-hostable KDNA entitlement service for license activation, synchronization, revocation, and signed status records.","maintainers":[{"name":"code2mp4","email":"hi@code2mp4.com"}],"readme":"# @aikdna/kdna-activation-server\n\n**Experimental self-hostable HTTP activation server for KDNA `licensed` assets.**\n\nKDNA makes judgment portable across models and runtimes. This repository is an\nexperimental entitlement reference implementation, not a marketplace, billing\nservice, or AIKDNA-hosted activation platform.\n\nThis package implements the legacy license-key and signed-receipt profile. It\nis not an RFC-0019 account/device external-key-grant issuer. Implementations\nmust not present one profile as the other.\n\nThe registry package at `0.2.0` is the published baseline. Repository\n`0.2.1` is an unreleased source candidate containing the secret-input and\nverifier-at-rest corrections below; it is not npm latest and a checkout is not\nevidence of publication.\n\nThis server answers one question:\n\n> Is this user / device / organisation currently entitled to use this\n> asset?\n\nIt implements the four endpoints in\n[`specs/kdna-entitlement-api.md`][1] and the self-hosting invariant\nfrom [`docs/REMOTE_MODE.md`][2].\n\nThe responsibility routes documented below are the only public HTTP contract.\nIn particular, Remote 0.4.1 and later send entitlement refreshes to\n`/entitlements/sync`; deploy Activation 0.2.0 before Remote 0.4.1 or later.\nThe server validates every entitlement `domain` against the authoritative\n`asset_id` grammar shipped by KDNA Core 0.21.0.\n\n[1]: https://github.com/aikdna/kdna/blob/main/specs/kdna-entitlement-api.md\n[2]: https://github.com/aikdna/kdna/blob/main/docs/REMOTE_MODE.md\n\n---\n\n## Self-hosting is the default\n\n> The KDNA protocol MUST NOT assume a single official KDNA\n> server. Any asset creator can run their own activation server.\n> No AIKDNA-hosted activation service is part of the current public baseline.\n\nThis server is the deployer's own. The protocol does not\nhardcode any KDNA Inc. URL. The admin token is deployer-\ncontrolled. License records are deployer-controlled. The\nserver's signing keypair is generated on first start and\nstored locally.\n\n---\n\n## Quick start (self-hosting)\n\n```bash\n# 1. Start from a trusted exact 0.2.1 source checkout on Node 18+.\nnpm ci\nnpm test\nnpm pack\nnpm install -g ./aikdna-kdna-activation-server-0.2.1.tgz\n\n# 2. Create private input files without placing secrets in shell arguments.\ninstall -m 600 /dev/null ./license-request.json\n${EDITOR:?Set EDITOR} ./license-request.json\nkdna-activation-server --create-license-file ./license-request.json\nrm ./license-request.json\n\ninstall -m 600 /dev/null ./admin-token\n${EDITOR:?Set EDITOR} ./admin-token\n\n# 3. Start the server. The token file must remain private.\nkdna-activation-server --port 3001 --admin-token-file ./admin-token\n\n# 4. Test. Create the request body with a private editor, not inline argv.\ncurl http://localhost:3001/healthz\ninstall -m 600 /dev/null ./activation-request.json\n${EDITOR:?Set EDITOR} ./activation-request.json\ncurl -X POST http://localhost:3001/entitlements/activate \\\n  -H 'Content-Type: application/json' \\\n  --data-binary @./activation-request.json\nrm ./activation-request.json\n```\n\nThat's it. No registration, no phone-home, no KDNA Inc. URL.\nDo not replace a placeholder with a real secret inside a command argument.\n`--create-license-stdin` and `--admin-token-stdin` are available when a\ndeployer's secret provider can pipe bounded strict UTF-8 directly.\nThe CLI rejects unknown options, unexpected positional values, duplicate\noptions, cross-mode combinations, and values attached to boolean stdin flags;\nthese errors never echo the rejected token.\n\n---\n\n## HTTP API\n\n### `GET /healthz`\n\nHealth check. Returns 200 with server metadata.\n\n### `GET /server/identity`\n\nReturns the server's Ed25519 public key (PEM, hex, and\nfingerprint). Clients use this to verify that an entitlement\nrecord was really signed by this server.\n\n### `POST /entitlements/activate`\n\nActivates a license. Returns a signed entitlement record\n(cryptographically verifiable against `/server/identity`).\n\nRequest body:\n\n```json\n{\n  \"domain\": \"kdna:yourname:your-asset\",\n  \"license_key\": \"<license-secret>\",\n  \"machine_fingerprint\": \"<sha256>\"\n}\n```\n\nOptional: `client`, `client_version`, `agent`, `account_id`,\n`device_label`.\n\n`machine_fingerprint` is required when the license was created with\n`require_machine_binding: true` (the default). Its canonical wire format is\nexactly 64 lowercase hexadecimal characters: the SHA-256 digest produced by\nthe client. Uppercase, prefixed, whitespace-padded, non-ASCII, short, and long\nforms are rejected rather than normalized into aliases.\n\nResponse (200): the signed entitlement record (see\n`specs/kdna-entitlement-api.md` §5). The response and its signed body never\ncontain `license_key`; clients only send that secret in activation and sync\nrequest bodies.\n\n`domain` is the entitlement contract field for the Core manifest `asset_id`.\nIts value must satisfy the canonical asset identity grammar from Core 0.21.0's\npublished `manifest.schema.json`. No alternate package-name syntax is accepted\nas a second identity format.\n\nErrors:\n- `INVALID_LICENSE_KEY` (404) — key does not match the domain\n- `LICENSE_REVOKED` (403) — license has been revoked\n- `LICENSE_EXPIRED` (403) — `expires_at` is in the past\n- `MISSING_MACHINE_FINGERPRINT` (400) — a bound license omitted its fingerprint\n- `INVALID_MACHINE_FINGERPRINT` (400) — the fingerprint is not canonical\n- `MACHINE_MISMATCH` (403) — the license is bound to another machine or has\n  not yet been activated on this machine\n\n### `POST /entitlements/sync`\n\nRefreshes the entitlement state (updates `last_checked_at` and\n`offline_valid_until`). `domain` and `license_key` are required;\n`license_id` is optional but, when present, must identify that same license.\nMachine-bound licenses must already have been activated and must send the same\ncanonical `machine_fingerprint`. Returns the signed record. Same errors as\n`/activate`.\n\n### `POST /entitlements/revoke` (admin)\n\nRevokes a license. Requires an `Authorization: Bearer\n<admin-token>` header. The admin token is set at server\nstartup.\n\nRequest body:\n\n```json\n{\n  \"license_id\": \"lic_abc123\",\n  \"domain\": \"kdna:yourname:your-asset\",\n  \"reason\": \"payment_failed\",\n  \"revoked_by\": \"billing-system\"\n}\n```\n\n### `GET /entitlements/status?domain=...&license_id=...&machine_fingerprint=...`\n\nIntrospection. Returns public entitlement metadata (unsigned,\nfor introspection only) and does not include `license_key`.\nBoth the canonical scoped `domain` and `license_id` are required. The status\nendpoint rejects `license_key` entirely so the secret cannot appear in URLs or\naccess logs; use `/activate` or `/sync` for signed entitlement records.\nFor machine-bound licenses, status requires the already-bound canonical\nfingerprint and never creates a first binding. Error responses do not include\nlicense metadata, the submitted fingerprint, or the stored binding digest.\nMissing, malformed, mismatched, and not-yet-bound machine authorization all\nreturn the same `NOT_FOUND` response as an unknown record, so public\n`license_id` values cannot be used as a binding-enumeration oracle.\n\n---\n\n## CLI\n\n```bash\n# Create a license (one-shot) from a private request body\nkdna-activation-server --create-license-stdin < ./license-request.json\n# or: kdna-activation-server --create-license-file ./license-request.json\n\n# List all licenses\nkdna-activation-server --list\n\n# Revoke\nkdna-activation-server --revoke lic_abc123 --reason \"payment_failed\"\n\n# Start the server with one private token source\nkdna-activation-server --port 3001 --admin-token-file ./admin-token\n# or: kdna-activation-server --port 3001 --admin-token-stdin\n```\n\nThe server keypair is auto-generated on first start and\nstored at `~/.kdna/activation-server/`. The private key is\nmode 0600.\n\n---\n\n## Security properties\n\n- **No KDNA Inc. URL is hardcoded.** The server has zero\n  outbound network calls during normal operation.\n- **The server keypair is local.** The private key never\n  leaves the deployer's machine.\n- **The admin token is deployer-controlled.** Set it at\n  startup through bounded strict UTF-8 stdin or a private regular file, or omit\n  it to disable `/revoke` over HTTP. Raw `--admin-token` argv is rejected.\n- **The license_key is a request secret.** It is accepted only in activation\n  and sync JSON request bodies. The server does not return it in signed\n  records, status responses, errors, or command output. Clients should not\n  place it in URLs, argv, or logs. License creation reads private JSON through\n  stdin or a private file; raw `--create-license` argv is rejected.\n- **License secrets are verifier-only at rest.** New records store an\n  independently salted, bounded-parameter scrypt verifier, never the plaintext\n  `license_key`. Verification is constant-time. A legacy plaintext record is\n  atomically rewritten only after the caller supplies the exact old secret;\n  failed verification or concurrent drift leaves the original bytes intact.\n  Salt and verifier bytes are server-only and are not usable as a license key.\n- **Records are signed.** Every `/activate` and `/sync`\n  response is signed with the server's Ed25519 key. Clients\n  can verify against `/server/identity`.\n- **Raw machine fingerprints are not stored by new activations.** The server\n  derives a purpose-separated HMAC key from its local private key and stores\n  only the keyed binding digest. A matching request migrates an older raw\n  fingerprint record in place; malformed legacy bindings fail closed.\n- **License record filenames are collision-free.** Each validated license\n  identifier has one encoded storage path. Exact legacy records migrate on\n  write, while a different identifier that shared an older sanitized filename\n  is never treated as an alias. Directory scans only discover identifiers;\n  activation, listing, and key lookup always re-read the authoritative path.\n- **HTTP routing is origin-form only.** Requests require one syntactically\n  valid `Host` header, while route selection uses a fixed internal base rather\n  than the supplied host. Absolute request targets and Host values containing\n  credentials, paths, queries, or fragments are rejected.\n- **JSON bodies are byte-bounded and strictly decoded.** Activation, sync, and\n  revocation accept at most 64 KiB of UTF-8 bytes. Oversized, malformed UTF-8,\n  and malformed JSON inputs receive stable errors without parser details.\n\n---\n\n## Local development\n\n```bash\ngit clone https://github.com/aikdna/kdna-activation-server\ncd kdna-activation-server\nnpm test\n```\n\nThe tests spin up the server on an OS-assigned port. No\nexternal services are required.\n\n---\n\n## License\n\nApache 2.0. See [LICENSE](./LICENSE).\n\nThis server is a license-management reference implementation.\nTrust is the consumer's decision, not the server's claim.\n","readmeFilename":"README.md"}