Docs polish: active-pill sync, license-sidebar bug fix, pricing standardized, ~70 em-dashes removed
- docs.js (new): sync sidebar .active pill with location.hash on load, click, and hashchange so in-page anchor links (Architecture, Discount codes, Backups, etc.) update the pill instead of leaving it stuck on whatever was statically marked - Wire docs.js into every page just before </body> - license.html: sidebar Project/Operate order matches every other page (Project first) - pricing.html: rewritten to use the standard docs layout (full sidebar groups, prose main, breadcrumb) instead of a one-off shell that felt detached from the rest of the docs - Reference section: remove Admin API + SDKs anchor links (they masqueraded as separate pages but just scrolled within integrate.html); Wire format stands alone - Pricing copy: Zaprite reframed as "expanded payment options including card payment capabilities", "shipping in v0.3" removed (it shipped), Patron rephrased as perpetual (never expires or renews) - "Toggling inactive" cap-evasion language replaced — admin UI exposes delete only, no soft-disable affordance for products - ~70 em-dashes removed across 8 pages using a small pattern set (elaboration→period, list-intro→colon, tight clarification→comma, parentheticals→parens). Decorative stamp ornaments and references to actual third-party UI labels are kept verbatim.
This commit is contained in:
+11
-12
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Keysat Docs — Wire format reference</title>
|
||||
<title>Keysat Docs: Wire format reference</title>
|
||||
<link rel="icon" type="image/svg+xml" href="assets/favicon.svg">
|
||||
<link rel="stylesheet" href="docs.css">
|
||||
</head>
|
||||
@@ -33,8 +33,6 @@
|
||||
<div class="group">
|
||||
<div class="glabel">Reference</div>
|
||||
<a href="wire-format.html" class="active">Wire format</a>
|
||||
<a href="integrate.html#api">Admin API</a>
|
||||
<a href="integrate.html#sdks">SDKs</a>
|
||||
</div>
|
||||
<div class="group">
|
||||
<div class="glabel">Project</div>
|
||||
@@ -61,9 +59,9 @@
|
||||
|
||||
<p>Three parts, separated by single dashes:</p>
|
||||
<ul>
|
||||
<li><code>LIC1</code> — literal envelope tag. Future format revisions get a new tag (<code>LIC2</code> etc.). Parsers MUST reject unknown tags.</li>
|
||||
<li><code><base32 payload></code> — the signed payload bytes, RFC 4648 base32 without padding (case-insensitive on decode). Variable length depending on payload version and number of entitlements.</li>
|
||||
<li><code><base32 signature></code> — the 64-byte Ed25519 signature over the <em>raw payload bytes</em>, base32-encoded the same way.</li>
|
||||
<li><code>LIC1</code>: literal envelope tag. Future format revisions get a new tag (<code>LIC2</code> etc.). Parsers MUST reject unknown tags.</li>
|
||||
<li><code><base32 payload></code>: the signed payload bytes, RFC 4648 base32 without padding (case-insensitive on decode). Variable length depending on payload version and number of entitlements.</li>
|
||||
<li><code><base32 signature></code>: the 64-byte Ed25519 signature over the <em>raw payload bytes</em>, base32-encoded the same way.</li>
|
||||
</ul>
|
||||
<p>To verify: split on <code>-</code>, validate the tag is <code>LIC1</code>, base32-decode both chunks (case-fold to upper), parse the payload, and verify the signature bytes against the raw payload bytes using the issuer’s Ed25519 public key.</p>
|
||||
|
||||
@@ -71,7 +69,7 @@
|
||||
<p>Keysat ships two payload versions today. v2 is the current default that the daemon issues; v1 verifiers stay in the SDKs forever so legacy keys keep verifying.</p>
|
||||
|
||||
<h3>v1 (legacy, fixed 74 bytes)</h3>
|
||||
<p>Issued by the very early daemon builds. No expiry, no entitlements — perpetual only, fingerprint binding optional. Still accepted on parse so old customer keys don’t break.</p>
|
||||
<p>Issued by the very early daemon builds. No expiry, no entitlements. Perpetual only, fingerprint binding optional. Still accepted on parse so old customer keys don’t break.</p>
|
||||
<table class="t">
|
||||
<thead><tr><th>Offset</th><th>Length</th><th>Field</th><th>Notes</th></tr></thead>
|
||||
<tbody>
|
||||
@@ -85,7 +83,7 @@
|
||||
</table>
|
||||
|
||||
<h3>v2 (current default, variable length)</h3>
|
||||
<p>83-byte fixed head + variable-length entitlements table. v2 adds expiry, trial flag, and entitlements — all signed so offline verifiers can gate features without contacting the server (a stripped entitlement or pushed-back expiry would have to match a valid signature, which the attacker can’t produce).</p>
|
||||
<p>83-byte fixed head + variable-length entitlements table. v2 adds expiry, trial flag, and entitlements, all signed so offline verifiers can gate features without contacting the server (a stripped entitlement or pushed-back expiry would have to match a valid signature, which the attacker can’t produce).</p>
|
||||
<table class="t">
|
||||
<thead><tr><th>Offset</th><th>Length</th><th>Field</th><th>Notes</th></tr></thead>
|
||||
<tbody>
|
||||
@@ -102,7 +100,7 @@
|
||||
</table>
|
||||
|
||||
<h2 id="signature">Signature</h2>
|
||||
<p>The signature is computed over the <strong>raw payload bytes</strong> — the binary head plus any entitlements table, without the version tag, without base32 encoding, without dashes. The two base32 chunks in the wire format are encoded <em>independently</em>; concatenating them and base32-decoding the whole would be wrong.</p>
|
||||
<p>The signature is computed over the <strong>raw payload bytes</strong>: the binary head plus any entitlements table, without the version tag, without base32 encoding, without dashes. The two base32 chunks in the wire format are encoded <em>independently</em>; concatenating them and base32-decoding the whole would be wrong.</p>
|
||||
<p>Verify with the issuer’s Ed25519 public key (PEM-encoded, SubjectPublicKeyInfo). The SDKs ship the public key bundled in your app at build time; they don’t fetch it at runtime. (The whole point of offline verification is that a network-level attacker can’t hand your software a different key.)</p>
|
||||
|
||||
<h2 id="encoding">Base32 alphabet</h2>
|
||||
@@ -132,7 +130,7 @@ MCowBQYDK2VwAyEAmz7q8r4t1v…h3k2pXq9wL
|
||||
<li>Implement RFC 4648 base32 decode (most languages have this in stdlib).</li>
|
||||
<li>Implement the binary unmarshal for both v1 and v2 payloads (~80 lines total, mostly big-endian integer reads).</li>
|
||||
<li>Wire it up to your language’s Ed25519 verifier from a vetted crypto library (libsodium, ring, ed25519-dalek, the Node/Python stdlib, etc.).</li>
|
||||
<li>Run the cross-check tests — if all three vector cases pass byte-for-byte, you’re wire-compatible.</li>
|
||||
<li>Run the cross-check tests. If all three vector cases pass byte-for-byte, you’re wire-compatible.</li>
|
||||
</ol>
|
||||
|
||||
<p>The four official SDKs (Rust, TypeScript, Python, Go) all sit on top of these same fixtures and the daemon’s test suite asserts each implementation round-trips them identically before a release ships.</p>
|
||||
@@ -142,8 +140,8 @@ MCowBQYDK2VwAyEAmz7q8r4t1v…h3k2pXq9wL
|
||||
|
||||
<ul>
|
||||
<li>Never silently changing an existing layout. Any field-shape change ⇒ new version byte.</li>
|
||||
<li>Maintaining v1 + v2 verifier support indefinitely — if v3 ever ships, your existing customer keys still verify against the daemon and the SDKs they shipped with.</li>
|
||||
<li>The wire-envelope tag (<code>LIC1-…</code>) bumps only on a breaking envelope change — new payload versions live inside the same envelope tag as long as the split-on-dash structure stays the same.</li>
|
||||
<li>Maintaining v1 + v2 verifier support indefinitely. If v3 ever ships, your existing customer keys still verify against the daemon and the SDKs they shipped with.</li>
|
||||
<li>The wire-envelope tag (<code>LIC1-…</code>) bumps only on a breaking envelope change. New payload versions live inside the same envelope tag as long as the split-on-dash structure stays the same.</li>
|
||||
<li>Publishing test vectors for every payload version under <code>tests/crosscheck/</code> in the daemon repo. All five implementations (daemon, Rust SDK, TypeScript SDK, Python SDK, Go SDK) are required to round-trip the same vectors byte-for-byte before a release ships.</li>
|
||||
</ul>
|
||||
</main>
|
||||
@@ -162,5 +160,6 @@ MCowBQYDK2VwAyEAmz7q8r4t1v…h3k2pXq9wL
|
||||
|
||||
<script src="https://unpkg.com/lucide@latest"></script>
|
||||
<script>lucide.createIcons();</script>
|
||||
<script src="docs.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user