843ff0e5d7
Glue files not covered by subproject repos: top-level docs, logo, keysat-design-system, and crosscheck tests. Subproject folders are gitignored (each has its own Gitea remote).
71 lines
3.2 KiB
Markdown
71 lines
3.2 KiB
Markdown
# Format cross-check
|
|
|
|
Verifies that the three implementations of the `LIC1-...-...` key format
|
|
(licensing-service in Rust, licensing-client-rust SDK, licensing-client-ts SDK)
|
|
all agree, byte for byte, on **both** the legacy v1 payload layout and the
|
|
current v2 layout.
|
|
|
|
## Approach
|
|
|
|
1. `reference_signer.py` builds three license keys from scratch using the exact
|
|
byte layouts documented in `licensing-service/src/crypto/mod.rs`. It uses
|
|
Python's `cryptography` for Ed25519 signing — an independent implementation
|
|
from the Rust one, so agreement here is strong evidence the format is
|
|
correct, not just that the Rust side agrees with itself.
|
|
|
|
The three keys exercise every branch of the parser:
|
|
|
|
- **`v1`** — legacy fixed-74 payload, fingerprint-bound. New keys aren't
|
|
issued in v1 anymore, but SDKs must still accept them indefinitely so
|
|
old keys in the wild keep working.
|
|
- **`v2`** — trial key, fingerprint-bound, with explicit expiry and two
|
|
entitlements. Stresses the variable-length tail parser.
|
|
- **`v2_perpetual_unbound`** — the "happy path" for a normal paid purchase:
|
|
v2, no expiry, no fingerprint binding, no entitlements.
|
|
|
|
2. `run_ts.mjs` imports the built TypeScript SDK (`dist/index.js`) and runs
|
|
each of the three fixtures through: field-by-field parse, signature
|
|
verification, fingerprint binding (positive + negative), entitlement
|
|
lookup, `isExpiredAt` boundaries, and tamper detection. Also spot-checks
|
|
`hashFingerprint` against Python's `hashlib.sha256` and public-key loading.
|
|
|
|
## Rust SDK coverage
|
|
|
|
The Rust SDK uses the same crates as the service (`data_encoding::BASE32_NOPAD`,
|
|
`ed25519_dalek`) with identical byte offsets (`licensing-client-rust/src/key.rs`
|
|
mirrors `licensing-service/src/crypto/mod.rs`), so round-trip compatibility is
|
|
guaranteed by construction. If you change the layout, update the service's
|
|
`from_bytes`, the Rust SDK's `from_bytes`, and `reference_signer.py` together.
|
|
|
|
The Rust SDK's own unit tests (`cargo test -p licensing-client`) round-trip
|
|
every flag + version combination.
|
|
|
|
## Running
|
|
|
|
```bash
|
|
# Build the TS SDK first.
|
|
cd licensing-client-ts
|
|
npm install
|
|
npm run build
|
|
|
|
cd ../tests/crosscheck
|
|
python3 reference_signer.py > vector.json
|
|
node --experimental-vm-modules run_ts.mjs
|
|
```
|
|
|
|
## Current test vectors
|
|
|
|
Both vectors share a deterministic signing key seeded with `bytes(range(32))`,
|
|
so the license strings in `vector.json` are stable across regenerations (a
|
|
regression in encoding will produce a git diff).
|
|
|
|
| fixture | version | expires_at | entitlements | flags |
|
|
|------------------------|---------|-------------|------------------|-----------------------------------------|
|
|
| `v1` | 1 | (n/a) | (n/a) | `FINGERPRINT_BOUND` |
|
|
| `v2` | 2 | 1900000000 | `["pro","multi-device"]` | `FINGERPRINT_BOUND \| TRIAL` |
|
|
| `v2_perpetual_unbound` | 2 | 0 | `[]` | `0` |
|
|
|
|
Product UUID: `6f46a4f6-0d2f-4a28-b6aa-3e8fbf6f28f0`, fingerprint raw string
|
|
`"test-machine-fingerprint"` (SHA-256
|
|
`d34461ff63170de633b5aa2512ce2e15ac120b1c325acdada67c02e594ba3b3d`).
|