Skip to content

Commit fffc83d

Browse files
committed
feat: PC2 Media Runtime — server-side DASH/CENC decryption with Rust WASM
Built complete server-side media decryption pipeline so Elacity DRM-protected DASH video plays inside PC2's sandboxed iframe environment (no EME/CDM/ SharedArrayBuffer needed). - Rust `cenc-decrypt` WASM crate: fMP4 parser (moof/trun/senc/tenc), per-sample AES-128-CTR decryption, 16-byte IV support - Media API (`/api/media/*`): prepare-auth, init (MPD+CEK), segment (decrypt+strip+stream) - Lightweight MSE player: JavaScript-only, no browser DRM dependencies - DRM stripping: init segments (encv→av01, remove sinf/pssh) + media segments (remove senc/saiz/saio, fix trun.data_offset) - Two-phase Lit auth: server prepares SIWE+ReCap, user signs in market - Smart Account aware PSSH selection via Base factory contract - MPD parser + session manager for multi-track playback - Updated docs (SESSION_HANDOVER.md, ROADMAP.md) with media runtime Made-with: Cursor
1 parent fe40462 commit fffc83d

27 files changed

Lines changed: 3585 additions & 68 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,7 @@ pc2-node/test-*.js.map
5353

5454
# Rust build artifacts
5555
**/target/
56+
57+
# Runtime data (IPFS datastore, supernode cache)
58+
data/ipfs/
59+
data/supernodes.json

docs/core/ROADMAP.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ These diagrams from Rong define the north star. Every work stream should move us
165165
- [x] Universal asset viewer — **server-side secure viewer** for images (Sharp), PDFs (PDF.js+Canvas hybrid), text (Canvas) with watermarking, buffer zeroing, auto-decrypt, parallel PDF page loading *(completed Mar 15)*
166166
- [x] **WASM Renderer** — Rust crate compiled to `wasm32-wasip1` for text rendering inside isolated WASM linear memory + `WASMRuntime.ts` Node.js WASI host *(completed Mar 15)*
167167
- [x] **dDRM Viewer app** — dedicated PC2 app with two display modes (centered images, full-width scrollable documents), anti-piracy measures, renderer badges, puter.args IPC integration *(completed Mar 15)*
168+
- [x] **PC2 Media Runtime** — complete server-side DASH/CENC decryption pipeline. Rust `cenc-decrypt` WASM crate (AES-128-CTR per-sample decryption), MSE player (no EME/CDM/SharedArrayBuffer), DRM signaling stripping (`encv→av01`, `sinf`/`senc` removal), 16-byte IV support from tenc, Smart Account PSSH selection, two-phase Lit auth. **First successful end-to-end playback of Elacity DRM video inside PC2** *(completed Mar 16)*
168169
- [x] **dDRM Viewer native windowing** — launches as UIWindow via IPC `postMessage``launch_app()` (not browser popup), integrated with taskbar *(completed Mar 15)*
169170
- [x] **.ddrm.json capsule format** — descriptor files for non-media assets with CID, Lit params, mimeType. MIME: `application/x-ddrm+json`. Saved to Documents *(completed Mar 15)*
170171
- [x] **GUI capsule integration** — custom shield icon, MIME registration, double-click opens dDRM Viewer, content_type_to_icon mapping *(completed Mar 15)*
@@ -292,6 +293,7 @@ These diagrams from Rong define the north star. Every work stream should move us
292293
- [x] **WASM Renderer** — Rust→WASM text rendering + WASMRuntime.ts WASI host *(completed Mar 15)*
293294
- [x] **dDRM Viewer** — dedicated secure viewer app with native PC2 windowing, scrollable document view, .ddrm.json capsule support *(completed Mar 15)*
294295
- [x] **GUI file type integration**`.ddrm.json` icon, MIME, double-click → dDRM Viewer *(completed Mar 15)*
296+
- [x] **PC2 Media Runtime** — server-side DASH/CENC decryption: Rust WASM cenc-decrypt crate + MSE player + DRM stripping + Lit CEK recovery. End-to-end video playback verified *(completed Mar 16)*
295297
- [ ] **Lit Chipotle migration** — Datil deprecated ~April 25, 2026. Replace v7 SDK with REST API. CRITICAL PATH.
296298
- [ ] On-chain content indexer — replace Elacity GraphQL dependency with event scanner (The Graph / custom). See [DECENTRALIZATION_STATUS.md](./DECENTRALIZATION_STATUS.md) Tier 1.1
297299
- [ ] Self-provisioned RLI tokens — each PC2 node mints own capacity credits, removes Elacity wallet dependency. See Tier 1.3
@@ -525,7 +527,7 @@ These diagrams from Rong define the north star. Every work stream should move us
525527
> See [ELACITY_UNIVERSAL_ASSET_STRATEGY.md](./ELACITY_UNIVERSAL_ASSET_STRATEGY.md) for full strategy.
526528
527529
```
528-
Phase 1 — Media Foundation (M2-M3) ✅ LARGELY COMPLETE:
530+
Phase 1 — Media Foundation (M2-M3) ✅ COMPLETE:
529531
Integrate dDRM SDK → encrypted content upload → access tokens
530532
→ marketplace UI → buyer downloads → buyer becomes seeder
531533
→ app.json manifest spec with dDRM capability declaration

docs/core/SESSION_HANDOVER.md

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
**Release:** v1.1.0 tagged and released on 2026-03-03 (134 commits squash-merged to main)
1111
**Launcher:** v1.1.1 released — version display, one-click updates, full networking install
1212
**DAO Proposal:** Live at https://elastos.com/proposals/69a24f49247f130078064edd
13-
**Last Commit:** feat: dDRM Viewer app, .ddrm.json capsules, WASM renderer, full GUI integration
13+
**Last Commit:** feat: PC2 Media Runtime — server-side DASH/CENC decryption, Rust WASM cenc-decrypt, MSE player, end-to-end DRM video playback
1414

1515
### What Just Shipped (v1.1.0 on main)
1616

@@ -44,13 +44,23 @@
4444
- **Media preview** — inline player for content previews
4545
- **Creator avatars** — resolved from IPFS with proper fallback
4646

47-
#### DRM Playback — WORKING END-TO-END
47+
#### DRM Playback — WORKING END-TO-END (TWO PIPELINES)
48+
49+
**Pipeline 1: Elacity Player (legacy, for `.edrm` files)**
4850
- **`.edrm` file double-click** → launches Elacity Player in a dedicated popup window (required for `SharedArrayBuffer`/COOP/COEP)
4951
- **Lit Protocol DRM** — license acquisition, signature verification, decryption all working; `@lit-protocol/*` pinned to v7.3.0 via npm overrides
50-
- **Local IPFS playback** — player loads content from local Helia node (`localhost:4200/ipfs/`) with fallback to Elacity CDN
51-
- **UnixFS DAG path resolution**`/ipfs/:cid/*` wildcard route resolves nested paths within directory CIDs (DASH segments, manifests)
5252
- **Particle Universal Account** — SDK v1.0.24 integration fixed (removed `universalGas: true` for correct API shape)
5353

54+
**Pipeline 2: PC2 Media Runtime (NEW, server-side DASH/CENC decryption)**
55+
- **Server-side decryption** — PC2 node fetches encrypted DASH segments from local IPFS, decrypts via Rust WASM (`cenc-decrypt` crate), strips all DRM signaling, streams clear fMP4 to browser
56+
- **Lightweight MSE player** — JavaScript-only player using MediaSource Extensions. No EME, no CDM, no SharedArrayBuffer, no COOP/COEP needed. Works inside PC2 iframe sandbox
57+
- **Rust WASM `cenc-decrypt`** — parses fMP4 boxes (moof/trun/senc/tenc), performs per-sample AES-128-CTR decryption with correct 16-byte IV support. CEK stays in WASM linear memory
58+
- **DRM stripping** — init segments: `encv→av01`, `enca→mp4a`, remove `sinf`/`pssh`, adjust all ancestor box sizes. Media segments: remove `senc`/`saiz`/`saio`, fix `trun.data_offset`
59+
- **Two-phase Lit auth** — server prepares SIWE + ReCap message, user signs in market dApp, signature relayed back to init endpoint for CEK recovery
60+
- **Smart Account aware** — detects Universal Account via Base factory contract, selects correct PSSH for SA address
61+
- **Local IPFS playback** — content loaded from local Helia node (`localhost:4200/ipfs/`) with fallback to Elacity CDN
62+
- **UnixFS DAG path resolution**`/ipfs/:cid/*` wildcard route resolves nested paths within directory CIDs (DASH segments, manifests)
63+
5464
#### Decentralized CDN Network — COMPLETE (Mar 5-6)
5565
- **NAT Traversal**`@libp2p/circuit-relay-v2`, `@libp2p/dcutr`, `@libp2p/autonat` wired into Helia node for peer reachability behind NATs
5666
- **Bitswap-first fetching**`fetchViaBitswap()` method tries DHT `findProviders` + direct peer block exchange before falling back to HTTP gateways
@@ -334,13 +344,35 @@ Full technical spec at `docs/core/ACCESS_PACKAGE_SPEC.md`. Key decisions:
334344
- [x] **IPC.js args forwarding**`launchApp` handler passes structured `args` and `windowTitle` to `launch_app()` (Mar 15)
335345
- [x] **PDF scrollable view** — all pages stacked vertically with scroll, replacing single-page arrow navigation (Mar 15)
336346
- [x] **Text full-width view** — rendered text image fills window width for readability (Mar 15)
347+
- [x] **PC2 Media Runtime** — Rust WASM `cenc-decrypt` crate (AES-128-CTR per-sample, 16-byte IVs), MSE player (no EME/CDM), DRM stripping (init+segment), two-phase Lit auth, SA-aware PSSH selection. **End-to-end DASH video playback verified** *(completed Mar 16)*
337348
- [ ] Lit Chipotle migration — Datil network deprecated ~April 25, 2026, need to migrate to Chipotle REST API
338349

339350
**Known issues:**
340351
- Elacity frontend UA receipt parsing: `UAReceiptFetcher.enrichOperationsWithContracts` throws `TypeError` after successful on-chain purchase. Bug is in Elacity's frontend, not our code.
341352
- MPD parser error for image assets: Elacity's media player tries to parse image metadata as DASH manifest. Expected for non-video content.
342353
- Lit Datil deprecation: Datil network being deprecated ~April 25, 2026 in favor of Chipotle (REST API, API key auth, TEE-based). Migration required.
343354

355+
#### PC2 Media Runtime — WORKING END-TO-END (Mar 15-16)
356+
357+
Built a complete server-side DASH/CENC media decryption pipeline for PC2. Elacity's existing player relies on browser-native DRM (EME/CDM + SharedArrayBuffer) which can't work inside PC2's sandboxed iframes. The PC2 node now intercepts encrypted DASH streams, decrypts them server-side, strips all DRM signaling, and streams clear content to a lightweight MSE-based JavaScript player.
358+
359+
**Two WASM runtimes (both running):**
360+
- **`ddrm-renderer`** — Non-media assets (images, PDFs, text). Decrypts and renders to pixels server-side.
361+
- **`cenc-decrypt`** (NEW) — Media (video/audio). Rust crate → `wasm32-wasip1`. Parses fMP4 box structure (moof/trun/senc), performs per-sample AES-128-CTR decryption per CENC standard. CEK never leaves WASM linear memory.
362+
363+
**Key components built:**
364+
- `pc2-node/src/api/media.ts` — Three endpoints: `/api/media/prepare-auth` (Lit SIWE flow), `/api/media/init` (MPD parse + CEK recovery via Lit Protocol), `/api/media/segment` (fetch encrypted segment from IPFS → WASM decrypt → strip DRM → stream clear content)
365+
- `pc2-node/crates/cenc-decrypt/` — Rust CENC decryptor (mp4box parser, senc/trun/tenc extraction, AES-128-CTR per-sample decrypt with correct 16-byte IV support)
366+
- `pc2-node/data/test-apps/pc2-media-runtime/` + `data/installed-apps/pc2-media-runtime/` — Lightweight MSE player (no SharedArrayBuffer, no EME, no CDM)
367+
- `pc2-node/src/services/media/sessionManager.ts` — In-memory session store (CEK + MPD + init segments)
368+
- `pc2-node/src/services/media/mpdParser.ts` — DASH MPD XML parser
369+
- `stripEncryptionSignaling()` — Rewrites init segments: `encv→av01`, `enca→mp4a`, removes `sinf`/`pssh`, adjusts all ancestor box sizes
370+
- `stripSegmentEncryptionBoxes()` — Removes `senc`/`saiz`/`saio` from media segments, fixes `trun.data_offset`
371+
- Smart Account detection via Base factory contract for SA-aware PSSH selection
372+
- Two-phase Lit auth: server prepares SIWE + ReCap, user signs in market app, runtime relays to init
373+
374+
**Verified:** First successful end-to-end playback of Elacity DRM-protected DASH video inside PC2 (AV1 codec, AAC audio, 33.8s duration, 16-byte CENC IVs).
375+
344376
#### Next Up — Engineering Priorities
345377
1. **Lit Chipotle migration** — CRITICAL. Datil deprecated ~April 25, 2026. Replace v7 SDK with Chipotle REST API. Research at `docs/core/CHIPOTLE_MIGRATION_RESEARCH.md`.
346378
2. **WASM renderer hardening** — Extend Rust→WASM binary to handle PDF and image rendering (currently text only). Goal: CEK and plaintext never touch Node.js for any asset type.
@@ -426,6 +458,7 @@ Full technical spec at `docs/core/ACCESS_PACKAGE_SPEC.md`. Key decisions:
426458
- [3D Orb + SEO + Rebrand](6431d137-5dd9-4c8e-b042-5d8c54b908a5) — 3D orb integration, network map rebrand to "World Computer", full SEO overhaul, GA4, app icon fixes, mobile responsiveness
427459
- [dDRM Pipeline E2E](fd6755f0-d73c-4e41-8df3-0f57f15071a2)@elacity-js/access, Creator Dashboard, Lit Action trust model (Path A), capacity credit auto-detection, decrypt endpoint, decentralization analysis
428460
- [Secure Viewer & PDF](fd6755f0-d73c-4e41-8df3-0f57f15071a2) — secure viewer pipeline, PDF hybrid rendering, two-layer encryption fix, Lit Pinata/relayer integration, auto-decrypt, parallel pages, dDRM Viewer app, .ddrm.json capsules, WASM renderer, GUI integration
461+
- [Media Runtime E2E](fd6755f0-d73c-4e41-8df3-0f57f15071a2) — server-side DASH/CENC decryption pipeline, Rust WASM cenc-decrypt crate, MSE player, DRM stripping (init+segment), 16-byte IV fix, Smart Account PSSH, two-phase Lit auth
429462

430463
---
431464

@@ -490,6 +523,18 @@ Full technical spec at `docs/core/ACCESS_PACKAGE_SPEC.md`. Key decisions:
490523
| `pc2-node/data/test-apps/ddrm-viewer/app.json` | App manifest — capabilities (wallet, network, IPFS, DRM), display settings |
491524
| `pc2-node/src/api/apps.ts` | dDRM Viewer registration in app map with SVG icon |
492525

526+
#### PC2 Media Runtime (Mar 15-16)
527+
| File | Purpose |
528+
|------|---------|
529+
| `pc2-node/src/api/media.ts` | Media API — prepare-auth, init (MPD+CEK), segment (decrypt+strip+stream) |
530+
| `pc2-node/crates/cenc-decrypt/src/lib.rs` | WASM entry — orchestrates CENC decryption with tenc-derived IV size |
531+
| `pc2-node/crates/cenc-decrypt/src/mp4box.rs` | fMP4 box parser — trun, senc, tenc extraction with correct format header skipping |
532+
| `pc2-node/crates/cenc-decrypt/src/cenc.rs` | AES-128-CTR per-sample decryption (full-sample + subsample support) |
533+
| `pc2-node/wasm-apps/cenc-decrypt/cenc-decrypt.wasm` | Compiled WASM binary (wasm32-wasip1) |
534+
| `pc2-node/data/installed-apps/pc2-media-runtime/` | MSE player app (player.js, index.html) — lightweight, no EME/CDM |
535+
| `pc2-node/src/services/media/sessionManager.ts` | In-memory session store (CEK, tracks, init segments per track) |
536+
| `pc2-node/src/services/media/mpdParser.ts` | DASH MPD XML parser (tracks, segments, duration, codecs) |
537+
493538
#### WASM Renderer (Mar 15)
494539
| File | Purpose |
495540
|------|---------|

pc2-node/crates/cenc-decrypt/Cargo.lock

Lines changed: 208 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[package]
2+
name = "cenc-decrypt"
3+
version = "0.1.0"
4+
edition = "2021"
5+
description = "CENC (Common Encryption) AES-128-CTR decryptor for fMP4/DASH segments — runs in WASM sandbox"
6+
license = "MIT"
7+
8+
[lib]
9+
crate-type = ["cdylib", "rlib"]
10+
11+
[[bin]]
12+
name = "cenc-decrypt"
13+
path = "src/main.rs"
14+
15+
[dependencies]
16+
aes = "0.8"
17+
ctr = "0.9"
18+
base64 = "0.22"
19+
serde = { version = "1", features = ["derive"] }
20+
serde_json = "1"
21+
22+
[profile.release]
23+
opt-level = "s"
24+
lto = true
25+
codegen-units = 1
26+
strip = true

0 commit comments

Comments
 (0)