Skip to content

Commit 592a3be

Browse files
irzhywauclaude
andcommitted
feat(media/cenc): align pc2-node DRM packaging with MPEG-DASH/CENC and libav/MSE interop
End-to-end overhaul of the encrypted DASH/CENC packaging pipeline so that third-party CENC-aware consumers (libav, dashjs/MSE) can play pc2-node output, plus the supporting Lit/Chipotle integration prep, KID unification, MPD generator fixes, and documentation/tooling. Packaging (Rust + TS): * cenc-encrypt: process_transform_init iterates every trak in moov and wraps each sample entry in sinf/schm/tenc — audio init is no longer left as plain mp4a while segment bytes are encrypted * cenc-encrypt: per-codec clear-leader subsample encryption — 32 B for AV1 (preserves OBU headers, fixes obu_forbidden_bit decoder errors), 0 B + flag=0 senc for AAC (matches bento4) * cenc-encrypt: per-sample IV is a true global counter (seed + sample_index as BE u64) — eliminates cross-segment IV collisions under a shared CEK * cenc-encrypt: updated wasm configuration and ffmpeg codec detection hot path * dashPackager: per-Representation init.mp4 via mp4-split split_init — each rep declares exactly one trak, no more ghost streams * dashPackager: pssh placed only as last child of moov; root-level sibling rejected by Chromium MSE, in-moov-post-trak position required for libav per-stream side-data hydration * PSSH extraction switched from fragile marker-based scanning to full ISO/IEC 23001-7 box-walking so diverse JSON payloads are supported * MPEG-DASH manifest generator refined to comply with the standard KID unification (frontend creator + server): * hashToContentId removed — its dataToEncryptHash-derived bytes16 diverged from the KID embedded in pssh/tenc * on-chain bytes16 contentId now sources from the canonical pc2-node KID via new kidToContentId helper * .ddrm capsule kid sources from mediaEncodeResult.kid for media * /api/storage/lit/encrypt: non-media KID is 16-byte UUID-derived (was 32-byte randomBytes), bytes16-compatible * drafts schema: migration 34 adds kid TEXT column so draft-resume mints emit the correct contentId Verification tooling: * tools/verify-pssh-libav/verify-pssh.c — load-bearing C harness that replicates the libav consumer path (av_packet_side_data_get + av_encryption_init_info_get_side_data), walks AVEncryptionInitInfo->next, supports multi-systemId accept-list and --any / -q / -v / -vv verbosity, with Makefile + README * tools/scripts/verify-pssh-libav.sh — ffprobe-based operator smoke test * pc2-node/tests/media/pssh-discoverability.test.ts — synthetic placement assertions * pc2-node/tests/media/pssh-fixture.test.ts — real-asset fixture asserting encv/sinf/tenc structure, pssh box layout, and v3.0 JSON payload schema * pc2-node/tests/media/pssh-json-extract.test.ts — coverage for the new ISO box-walking extractor Documentation: * docs/core/MEDIA_DRM_PACKAGING.md — forward-looking engineering reference: pipeline diagram, on-wire CENC contract, Elacity dDRM v3.0 JSON schema, KID/CEK/IV roles, per-codec subsample rationale, verification tools, failure-mode runbook, roadmap, glossary, ISO/IEC references * docs/core/CENC_PACKAGING_COMPLIANCE.md — post-mortem covering the six independent defects, per-layer failure analysis, root-cause cascade, fix-by-fix table, file-by-file change list * CHIPOTLE_V3_PROTOCOL.md §14 rewritten — most prior CENC compliance gaps closed; remaining out-of-scope items called out (MPD ContentProtection, browser EME CDM, saiz/saio, per-OBU AV1 subsamples) * MEDIA-2026-04-28-DASH-MPD-COMPLIANCE cross-linked to the now-complete init-side work and the two new core docs * MEDIA-2026-05-18-CENC-PSSH-LIBAV-COMPLIANCE closed out (all 17 Phase 1-5 items, with inline notes for items that diverged from the original plan) Lit/Chipotle integration prep: * task scaffolding for the new Lit integration * relay bootstrap + connectivity groundwork carried forward from earlier iterative attempts (now consolidated) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent e5280e5 commit 592a3be

56 files changed

Lines changed: 7910 additions & 957 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Task: Chipotle V3 — Universal Encrypt/Decrypt Alignment
2+
3+
**Task ID**: CHIPOTLE-V3-UNIVERSAL-ACTIONS
4+
**Created**: 2026-05-18
5+
**Status**: InProgress (Phase 1 partially landed in `6bf1cddd6 "1st attempt"`)
6+
**Priority**: **P0 — Security + Architecture** — CEK must never appear in plaintext between components
7+
**Branch**: current HEAD (atop `6bf1cddd6`)
8+
**Owner**: Irzhy + Sasha
9+
**Related**: `SEC-2026-04-28-WAVE8-CHIPOTLE-HARDENING` (predecessor — C-02 kid binding),
10+
`LIT-ACTION-SIGNATURE-AUTH` (predecessor — session delegation),
11+
`docs/core/plans/chipotle_security_alignment.md` (specification)
12+
13+
## TL;DR
14+
15+
The Chipotle Lit Actions have been upgraded to a unified encrypt/decrypt model:
16+
17+
- **Encryption** returns `{ ciphertext, hash, signature, issuer }` with a composite
18+
hash `SHA-256(CEK ‖ KID ‖ authority)` that replaces the old `KID = sha256(CEK)[0:16]`
19+
binding.
20+
- **Decryption** wraps the CEK in an ECDH envelope using the requester's
21+
`sessionPublicKey` instead of returning it as plaintext. The requester
22+
unwraps locally.
23+
- **Media and non-media use the same actions** — no more separate code paths.
24+
25+
New CIDs:
26+
- Encrypt: `QmVEz3dDnQD1n96gMd2mFZWXdEDsRiPMumx86qMzhT35gY`
27+
- Decrypt: `QmPBjQD7V4aFTZPxUwZ9gDPFJtcJ4SvsJdTh3QexTyRBbj`
28+
29+
The PC2 node must align with these changes. Commit `6bf1cddd6` landed partial
30+
work (Lit Action files + encrypt-path scaffolding) but the decrypt path,
31+
protection data format, CID wiring, and ECDH envelope unwrapping are incomplete.
32+
33+
## Background
34+
35+
### What changed in the Lit Actions
36+
37+
1. **`universal-encrypt-chipotle.js`** (new, replaces `non-media-encrypt-chipotle.js`):
38+
- Accepts: `plaintext` (base64 CEK), `kid` (base64), `authority` (hex), `pkpId`
39+
- Computes composite hash: `SHA-256(cekBytes ‖ kidBytes ‖ authorityBytes)`
40+
- Signs the hash with the PKP's secp256k1 key
41+
- Encrypts CEK via `Lit.Actions.Encrypt({ pkpId, message: plaintext })`
42+
- Returns: `{ ciphertext, hash, signature, issuer }` (encoding via `outputFormat`)
43+
44+
2. **`universal-decrypt-chipotle.js`** (new, replaces both `non-media-decrypt-chipotle.js`
45+
and the old media decrypt):
46+
- Full session-bundle validation (delegation + request, same as V1.2 sigauth)
47+
- Recomputes and verifies composite hash binding (CEK ↔ KID ↔ authority)
48+
- Optional issuer signature verification
49+
- **Does NOT return plaintext CEK** — wraps it in an ECDH envelope:
50+
- ECDH key agreement: `deriveKey(pkpPrivateKey, sessionPublicKey)` → AES-CBC-256
51+
- IV = first 16 bytes of session public key
52+
- Plaintext layout: `metaLen | issuer(20B) | exp(8B) | audience(20B) | keyCount | cek`
53+
- Response includes metadata block (compressed PKP pubkey + signature + signer)
54+
- Supports `keyAlg: { name: "ECDH", namedCurve: "P-256" }` (required) or `{ name: "X25519" }`
55+
56+
### What `6bf1cddd6` ("1st attempt") already changed
57+
58+
| File | What landed | What's missing / broken |
59+
|---|---|---|
60+
| `data/lit-actions/universal-encrypt-chipotle.js` | ✅ Complete ||
61+
| `data/lit-actions/universal-decrypt-chipotle.js` | ✅ Complete ||
62+
| `chipotle-client.ts` | `EncryptParams` got `kid?`/`authority?`; `encryptWithLitAction` encodes raw bytes as base64 (was UTF-8), parses `hash`/`issuer`/`signature` from response | Still loads `non-media-encrypt-chipotle.js` not universal; doesn't pass `kid`/`authority` to jsParams; no unified decrypt function; no ECDH envelope unwrapping; no new CID constants |
63+
| `storage.ts` | Encrypt path passes raw CEK bytes; Datil path removed | Decrypt path untouched; default action CID still `bafkrei…` (V1.2 sigauth); no `kid`/`signature`/`issuer` in response |
64+
| `dashPackager.ts` | `encryptMediaCEK` passes raw CEK bytes (was UTF-8) | **REGRESSION**: `generateCEK` reverted to `kid = sha256(cek)[0:16]` (should be random UUID); `MEDIA_DECRYPT_ACTION_CID` not updated; `kid`/`authority` not passed to encrypt; protection data format not updated |
65+
| `media.ts` || Completely untouched |
66+
67+
## Requirements
68+
69+
### Must-have
70+
71+
- [ ] **CEK never in plaintext** between Lit Action response and the consuming
72+
component. All decrypt paths produce an ECDH envelope; the server
73+
unwraps locally using its ephemeral P-256 private key.
74+
- [ ] **Unified encrypt**: `encryptWithLitAction` calls `universal-encrypt-chipotle.js`
75+
with `kid`, `authority`, `outputFormat: "hex"`. KID is generated independently
76+
from CEK.
77+
- [ ] **Unified decrypt**: single function `recoverCEKViaEnvelope` replaces both
78+
`recoverNonMediaCEK` and the Datil ECDH path in `media.ts`. Generates
79+
P-256 ephemeral keypair, sends `publicKey` + `keyAlg` to Lit Action,
80+
receives ECDH envelope, unwraps to raw CEK.
81+
- [ ] **Protection data format** aligned with keystore service:
82+
`protocolVersion: "3.0"`, `signature`, `issuer`, `format: "hex"`,
83+
`algorithm` field, no `ciphersuite`.
84+
- [ ] **Legacy asset compatibility**: if `actionIpfsId` is present in protection
85+
data → use that CID (legacy action); if response `.data` is ≤16 bytes
86+
raw → treat as legacy plaintext CEK.
87+
- [ ] **CID constants updated**: default decrypt = `QmPBjQD7V4aFTZPxUwZ9gDPFJtcJ4SvsJdTh3QexTyRBbj`,
88+
encrypt = `QmVEz3dDnQD1n96gMd2mFZWXdEDsRiPMumx86qMzhT35gY`.
89+
- [ ] `keyAlg: { name: "ECDH", namedCurve: "P-256" }` explicitly in all decrypt calls.
90+
91+
### Should-have
92+
93+
- [ ] Documentation: `docs/core/CHIPOTLE_V3_PROTOCOL.md` covering full protocol.
94+
- [ ] `non-media-encrypt-chipotle.js` and `non-media-decrypt-chipotle.js` retained
95+
on disk but no longer loaded by default (legacy fallback only).
96+
97+
### Out of scope
98+
99+
- Player-side (`media-player/`) changes — handled separately.
100+
- Chipotle allowlist registration for the new CIDs (operational, not code).
101+
- Supernode `ddrm-config.json` updates (deployment step).
102+
103+
## Implementation Plan
104+
105+
See per-phase task files for detailed implementation:
106+
107+
- [x] **Phase 0**: Lit Action files landed — [`PHASE-0-LIT-ACTIONS.md`](./PHASE-0-LIT-ACTIONS.md)
108+
- [ ] **Phase 1**: Encryption path — [`PHASE-1-ENCRYPT.md`](./PHASE-1-ENCRYPT.md)
109+
- [ ] **Phase 2**: ECDH envelope unwrapping — [`PHASE-2-ECDH-UNWRAP.md`](./PHASE-2-ECDH-UNWRAP.md)
110+
- [ ] **Phase 3**: Unified decryption — [`PHASE-3-DECRYPT.md`](./PHASE-3-DECRYPT.md)
111+
- [ ] **Phase 4**: Protection data format — [`PHASE-4-PROTECTION-DATA.md`](./PHASE-4-PROTECTION-DATA.md)
112+
- [ ] **Phase 5**: Documentation — [`PHASE-5-DOCS.md`](./PHASE-5-DOCS.md)
113+
114+
## Acceptance Criteria
115+
116+
1. `cd pc2-node && npx tsc --noEmit` compiles cleanly.
117+
2. `POST /api/storage/lit/encrypt` returns `kid`, `signature`, `issuer`,
118+
`ciphertext`, `dataToEncryptHash` — all hex-encoded.
119+
3. `POST /api/storage/lit/secure-view` with a newly encrypted non-media asset
120+
recovers CEK via ECDH envelope (no plaintext CEK in Lit Action response).
121+
4. Media DASH packaging embeds new CIDs, `signature`, `issuer` in PSSH.
122+
5. Existing assets with old `actionIpfsId` still decrypt (legacy compatibility).
123+
6. No code path logs, caches, or transmits the raw CEK in plaintext between
124+
the Lit Action response and the AES-decrypt call.
125+
126+
## Files Modified
127+
128+
| File | Phase | Change |
129+
|---|---|---|
130+
| `pc2-node/src/api/chipotle-client.ts` | 1,2,3 | New CID constants, universal encrypt loader, `recoverCEKViaEnvelope`, ECDH unwrap |
131+
| `pc2-node/src/api/storage.ts` | 1,3,4 | Encrypt response, decrypt path, default CID, protection data |
132+
| `pc2-node/src/services/media/dashPackager.ts` | 1,4 | CID updates, independent KID, protection data format |
133+
| `pc2-node/src/api/media.ts` | 2,3 | Extract ECDH helpers, unified decrypt, remove Datil path |
134+
135+
## Files Created
136+
137+
| File | Phase | Purpose |
138+
|---|---|---|
139+
| `docs/core/CHIPOTLE_V3_PROTOCOL.md` | 5 | Full protocol documentation |
140+
| `.cursor/tasks/CHIPOTLE-V3-UNIVERSAL-ACTIONS/*.md` || This task + phase docs |
141+
142+
## Hard Constraints
143+
144+
- Do NOT delete `non-media-encrypt-chipotle.js` or `non-media-decrypt-chipotle.js`
145+
from disk — existing delegations may reference them.
146+
- Do NOT change the ECDH envelope wire format — the player-side decoder must
147+
stay compatible.
148+
- Do NOT log CEK bytes, CEK base64, or CEK hex at any log level.
149+
- Do NOT accept `rpc` from client/PSSH — always use `getBaseRpcUrl()` (M-01 fix).
150+
151+
## Status History
152+
153+
| Date | Status | Note |
154+
|---|---|---|
155+
| 2026-05-18 | InProgress | `6bf1cddd6` landed Lit Action files + partial encrypt scaffolding |
156+
| 2026-05-18 | InProgress | Task doc + phase breakdown created |
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Phase 0: Lit Action Files
2+
3+
**Status**: ✅ Done (landed in `6bf1cddd6`)
4+
5+
## What was done
6+
7+
Both universal Lit Action files were created and committed:
8+
9+
- `pc2-node/data/lit-actions/universal-encrypt-chipotle.js` (94 lines)
10+
- `pc2-node/data/lit-actions/universal-decrypt-chipotle.js` (587 lines)
11+
12+
These are the new Lit Action source files that Chipotle executes inside the TEE.
13+
They are complete and require no further changes.
14+
15+
## Encrypt action summary
16+
17+
Inputs: `plaintext` (base64 CEK), `kid` (base64), `authority` (hex), `pkpId`, `outputFormat`
18+
19+
1. Validates inputs (pkpId, authority must be valid addresses; kid + plaintext non-empty)
20+
2. Decodes CEK, KID, authority to bytes
21+
3. Computes composite: `SHA-256(cekBytes ‖ kidBytes ‖ authorityBytes)`
22+
4. Signs composite hash with PKP's secp256k1 key
23+
5. Encrypts CEK via `Lit.Actions.Encrypt({ pkpId, message: plaintext })`
24+
6. Returns `{ ciphertext, hash, signature, issuer }` encoded per `outputFormat`
25+
26+
## Decrypt action summary
27+
28+
Inputs: session bundle (delegation, delegationSig, request, requestSig),
29+
`ciphertext`, `dataToEncryptHash`, `kid`, `pkpId`, `authority`, `chainId`,
30+
`rpc`, `actionIpfsId`, `keyAlg`, `publicKey` (session P-256 pub hex)
31+
32+
1. Validates + verifies session bundle (identical to V1.2 sigauth)
33+
2. On-chain access check via `hasAccessByContentId`
34+
3. Decrypts CEK via `Lit.Actions.Decrypt({ pkpId, ciphertext })`
35+
4. Recomputes `SHA-256(cekBytes ‖ kidBytes ‖ authorityBytes)` — must match `dataToEncryptHash`
36+
5. Optional issuer signature verification
37+
6. Wraps CEK in ECDH envelope via `envelopeCEK()`:
38+
- ECDH(pkpPrivateKey, sessionPublicKey) → AES-CBC-256 shared key
39+
- IV = sessionPublicKey[0..15]
40+
- Encrypts rawLicenseBytes (metadata + CEK)
41+
- Signs encrypted body with PKP secp256k1
42+
7. Returns `{ data: base64(envelope), byteLength, authorizedAddress }`
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# Phase 1: Encryption Path
2+
3+
**Status**: Incomplete (scaffolding landed in `6bf1cddd6`, wiring not done)
4+
**Estimated effort**: ~2 hours
5+
**Files**: `chipotle-client.ts`, `dashPackager.ts`, `storage.ts`
6+
7+
## What `6bf1cddd6` already did
8+
9+
- `EncryptParams` interface: added optional `kid?: string`, `authority?: string`
10+
- `EncryptResult` interface: added optional `issuer?: string`, `signature?: string`
11+
- `encryptWithLitAction()`: CEK bytes → base64 (was UTF-8); parses `hash`/`issuer`/`signature` from response; fallback composite hash computation
12+
- `storage.ts` `/lit/encrypt`: passes raw CEK bytes (was UTF-8 of base64); Datil path removed
13+
- `dashPackager.ts`: `encryptMediaCEK` passes raw CEK bytes
14+
15+
## What's still broken / missing
16+
17+
### 1. `chipotle-client.ts` — encrypt code loader
18+
19+
**Current** (line ~494–510): `getChipotleEncryptCode()` loads `non-media-encrypt-chipotle.js`
20+
21+
**Required**: Load `universal-encrypt-chipotle.js` instead. Add new cached loader:
22+
23+
```typescript
24+
let cachedUniversalEncryptCode: string | null = null;
25+
26+
function getUniversalEncryptCode(): string {
27+
if (cachedUniversalEncryptCode) return cachedUniversalEncryptCode;
28+
const actionPath = join(DATA_DIR, 'lit-actions/universal-encrypt-chipotle.js');
29+
if (!existsSync(actionPath)) {
30+
throw new Error(`Universal encrypt Lit Action not found at ${actionPath}.`);
31+
}
32+
cachedUniversalEncryptCode = readFileSync(actionPath, 'utf8');
33+
return cachedUniversalEncryptCode;
34+
}
35+
```
36+
37+
Then in `encryptWithLitAction()`, change `getChipotleEncryptCode()``getUniversalEncryptCode()`.
38+
39+
### 2. `chipotle-client.ts` — pass `kid`/`authority`/`outputFormat` to jsParams
40+
41+
**Current** (line ~830): `jsParams: { pkpId, plaintext }`
42+
43+
**Required**:
44+
```typescript
45+
const jsParams: Record<string, unknown> = {
46+
pkpId,
47+
plaintext,
48+
kid: params.kid, // base64-encoded KID bytes
49+
authority: params.authority, // hex, 0x-prefixed
50+
outputFormat: 'hex',
51+
};
52+
```
53+
54+
The universal-encrypt action validates that `kid`, `authority`, and `plaintext` are non-empty and that `pkpId`/`authority` are valid addresses.
55+
56+
### 3. `chipotle-client.ts` — CID constants
57+
58+
Add near the top constants block:
59+
60+
```typescript
61+
const UNIVERSAL_ENCRYPT_CID = 'QmVEz3dDnQD1n96gMd2mFZWXdEDsRiPMumx86qMzhT35gY';
62+
const UNIVERSAL_DECRYPT_CID = 'QmPBjQD7V4aFTZPxUwZ9gDPFJtcJ4SvsJdTh3QexTyRBbj';
63+
```
64+
65+
Export them for use by `dashPackager.ts` and `storage.ts`.
66+
67+
### 4. `dashPackager.ts` — fix `generateCEK()` regression
68+
69+
**Current** (line 99–102, REGRESSED in `6bf1cddd6`):
70+
```typescript
71+
const cek = crypto.randomBytes(16);
72+
const kid = crypto.createHash('sha256').update(cek).digest().subarray(0, 16);
73+
return { cek, kid: kid.toString('hex') };
74+
```
75+
76+
**Required**: KID is independent of CEK:
77+
```typescript
78+
export function generateCEK(): { cek: Buffer; kid: string } {
79+
const cek = crypto.randomBytes(16);
80+
const kid = crypto.randomUUID().replace(/-/g, '');
81+
return { cek, kid };
82+
}
83+
```
84+
85+
### 5. `dashPackager.ts` — pass `kid` and `authority` to `encryptMediaCEK`
86+
87+
**Current** (line 107): `encryptMediaCEK(cek: Buffer)`
88+
89+
**Required**:
90+
```typescript
91+
export async function encryptMediaCEK(cek: Buffer, kid: string): Promise<EncryptResult> {
92+
// ...
93+
const result = await encryptWithLitAction({
94+
dataToEncrypt: cek,
95+
kid: Buffer.from(kid, 'hex').toString('base64'),
96+
authority: DEFAULT_AUTHORITY,
97+
accessControlConditions: conditions,
98+
});
99+
// ...
100+
}
101+
```
102+
103+
Update caller in `createEncryptedDASH` to pass `kid`.
104+
105+
### 6. `dashPackager.ts` — update CID constants
106+
107+
```typescript
108+
const MEDIA_DECRYPT_ACTION_CID = 'QmPBjQD7V4aFTZPxUwZ9gDPFJtcJ4SvsJdTh3QexTyRBbj';
109+
const MEDIA_ENCRYPT_ACTION_CID = 'QmVEz3dDnQD1n96gMd2mFZWXdEDsRiPMumx86qMzhT35gY';
110+
```
111+
112+
Or import from `chipotle-client.ts` to keep in sync.
113+
114+
### 7. `storage.ts` — encrypt endpoint: generate KID, pass to encrypt, return in response
115+
116+
**Current** (line ~2231): no KID generation, no kid/authority/signature/issuer in response
117+
118+
**Required** in `POST /lit/encrypt`:
119+
```typescript
120+
// Generate random 256-bit KID for non-media
121+
const kidBytes = crypto.randomBytes(32);
122+
const kidBase64 = kidBytes.toString('base64');
123+
const kidHex = kidBytes.toString('hex');
124+
125+
const chipotleResult = await encryptWithLitAction({
126+
dataToEncrypt: Buffer.from(cekBase64, 'base64'),
127+
kid: kidBase64,
128+
authority: DEFAULT_AUTHORITY,
129+
accessControlConditions: [],
130+
});
131+
132+
// Return extended response
133+
res.json({
134+
success: true,
135+
litCiphertext: chipotleResult.ciphertext,
136+
dataToEncryptHash: chipotleResult.dataToEncryptHash,
137+
kid: '0x' + kidHex,
138+
signature: chipotleResult.signature,
139+
issuer: chipotleResult.issuer,
140+
actionCid: effectiveActionCid,
141+
// ...existing fields...
142+
});
143+
```
144+
145+
## Checklist
146+
147+
- [ ] Add `getUniversalEncryptCode()` loader in `chipotle-client.ts`
148+
- [ ] Switch `encryptWithLitAction` to use `getUniversalEncryptCode()`
149+
- [ ] Pass `kid`, `authority`, `outputFormat: "hex"` in jsParams
150+
- [ ] Add + export `UNIVERSAL_ENCRYPT_CID` and `UNIVERSAL_DECRYPT_CID` constants
151+
- [ ] Fix `generateCEK()` regression in `dashPackager.ts` (random UUID KID)
152+
- [ ] Add `kid` parameter to `encryptMediaCEK()` and pass `kid`/`authority`
153+
- [ ] Update `MEDIA_DECRYPT_ACTION_CID` and `MEDIA_ENCRYPT_ACTION_CID`
154+
- [ ] Update `storage.ts` encrypt endpoint: generate KID, pass to encrypt, return in response
155+
- [ ] `tsc --noEmit` passes

0 commit comments

Comments
 (0)