feat(collab): add encrypted asset transfer - #13
Conversation
Room images now travel as ciphertext. The browser seals every asset under an HKDF-derived key (purpose `asset`, bound to room, authorization generation and the Excalidraw file id) before upload, so the app backend and the object store only ever hold bytes neither can read. Elements keep going through the relay unchanged; the two paths are aligned solely by the Plan 16 identity pair, which is why no new realtime message type was needed. - `@drawstuff/collaboration/asset`: versioned payload framing (data URL carried verbatim rather than JSON-escaped), MIME allowlist, byte budgets and `AssetCryptoCodec`; replaces Plan 16's manifest schema - `collaboration_asset` gains crypto_version, ut_file_key, url, byte_length (non-destructive `db:push`; the table held 0 rows) - `collaborationAsset.resolve` replaces `list`/`register`; assets enter a room only through a new uploadthing route that re-checks room access, role and generation inside the room lock, because an upload takes as long as its bytes - client asset store: store-wide transfer budget, batched lookups, deduplicated downloads, bounded body reads, backoff retry for "not uploaded yet" and permanent abandon for bytes that cannot be opened - retiring a generation enqueues its storage keys for the cleanup worker in the same transaction that deletes the rows, since object storage cannot join it Two Codex GPT-5.6 Sol review passes produced 12 findings: 9 accepted, 1 partially accepted, 2 rejected. Content-hash verification was rejected on evidence — an Excalidraw file id is the digest of the file the user picked while the stored data URL is the engine's resized re-encoding, so 41 of this project's 67 real assets would have been refused. The `deriveRoomKey`/`REALTIME_CRYPTO_VERSION` coupling was rejected as Plan 14 behaviour shared identically by snapshots; it and room-scoped retention are now owned by Plan 19. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (26)
📝 WalkthroughWalkthroughThe PR adds encrypted binary asset synchronization for collaboration rooms. It introduces room-scoped encryption, bounded transfer state, storage-backed uploads, requested-asset resolution, session integration, cleanup handling, and comprehensive tests. ChangesEncrypted collaboration asset transfer
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant CollaborationSession
participant AssetStore
participant AssetAPI
participant ObjectStorage
User->>CollaborationSession: add image to scene
CollaborationSession->>AssetStore: publish referenced local asset
AssetStore->>AssetAPI: upload encrypted ciphertext
AssetAPI->>ObjectStorage: store ciphertext
CollaborationSession->>AssetStore: request missing asset IDs
AssetStore->>AssetAPI: resolve asset records
AssetStore->>ObjectStorage: download ciphertext
AssetStore->>CollaborationSession: inject decrypted file
Possibly related PRs
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Room images now travel as ciphertext. The browser seals every asset under an HKDF-derived key (purpose
asset, bound to room, authorization generation and the Excalidraw file id) before upload, so the app backend and the object store only ever hold bytes neither can read. Elements keep going through the relay unchanged; the two paths are aligned solely by the Plan 16 identity pair, which is why no new realtime message type was needed.@drawstuff/collaboration/asset: versioned payload framing (data URL carried verbatim rather than JSON-escaped), MIME allowlist, byte budgets andAssetCryptoCodec; replaces Plan 16's manifest schemacollaboration_assetgains crypto_version, ut_file_key, url, byte_length (non-destructivedb:push; the table held 0 rows)collaborationAsset.resolvereplaceslist/register; assets enter a room only through a new uploadthing route that re-checks room access, role and generation inside the room lock, because an upload takes as long as its bytesTwo Codex GPT-5.6 Sol review passes produced 12 findings: 9 accepted, 1 partially accepted, 2 rejected. Content-hash verification was rejected on evidence — an Excalidraw file id is the digest of the file the user picked while the stored data URL is the engine's resized re-encoding, so 41 of this project's 67 real assets would have been refused. The
deriveRoomKey/REALTIME_CRYPTO_VERSIONcoupling was rejected as Plan 14 behaviour shared identically by snapshots; it and room-scoped retention are now owned by Plan 19.Summary by CodeRabbit
New Features
Bug Fixes
Documentation