feat(remote): verify server-CDM vault keys on the client and report bad pairs

The licence response lists KIDs a server vault supplied, the client proves them with the decode check, and a bad pair goes to the new session keys/bad route so the server flags its own row. Client vault keys go first over --remote, and the dashboard health warns when no SQLite vault can store flags.
This commit is contained in:
imSp4rky
2026-09-12 15:13:08 -06:00
parent 7c82282813
commit a7d6791136
21 changed files with 579 additions and 37 deletions
+12
View File
@@ -236,6 +236,17 @@ There are two ways DRM keys get resolved, chosen by the client's `server_cdm` fl
- Enable with `server_cdm: true` in the server entry.
- The server tells the client which DRM type it used
(`widevine` or `playready`).
- A content key the server took from its own vault is unproven. The response
lists its KID in `vault_keys`, the client decrypts and checks that the output
decodes, and a wrong pair goes back to `POST /api/session/{id}/keys/bad`. The
server flags the pair in every local vault it holds, records the name of the
vault that served it, and the next licence for that KID skips the pair and
reaches the CDM. A server with no local SQLite vault cannot store the flag. The
server accepts a report only for a pair it served to that remote session. The
client never learns the server vault names.
- A content key in the client's own vaults goes first, even when the server
already answered. The client proves it, and a server key waits as the next
candidate.
---
@@ -313,6 +324,7 @@ The server mounts all these routes, even in `--remote-only` mode. Paths use the
| `POST` | `/api/session/{id}/segments` | Resolve per-segment/track download descriptors |
| `POST` | `/api/session/{id}/segment_filter` | Unwanted HLS segment URIs for one track (ads, bumpers) |
| `POST` | `/api/session/{id}/license` | DRM licensing (proxy or server CDM) |
| `POST` | `/api/session/{id}/keys/bad` | Report a server-vault content key that did not decrypt |
| `GET` | `/api/session/{id}/logs` | Drain the service's server-side log output |
| `GET` | `/api/session/{id}/prompt` | Poll interactive auth status / pending prompt |
| `POST` | `/api/session/{id}/prompt` | Submit an answer to a pending prompt |