Small Grant: PrivRec - A Privacy-Preserving Screen & Camera Recorder

Monthly Grant Report - June 2026

Project: PrivRec

What progress was made on your grant this month?

This month PrivRec went from initial commit to a working end-to-end app covering nearly all of Milestone 1. The full pipeline now functions entirely client-side: a user onboards with a BIP-39 recovery phrase, records their screen or camera in the browser, encrypts and uploads the recording directly to Sia via the Sia JS SDK, picks a link expiry, and gets a shareable link. Recordings stream back out of Sia into a browser video player using MediaSource for progressive playback, with a full-buffer blob fallback for browsers without MSE.

Alongside the features, I invested in security and code quality: the Sia App Key is encrypted at rest with a non-extractable AES-GCM key held in IndexedDB (only ciphertext touches localStorage), the production build ships a strict Content-Security-Policy, and share/approval URLs are validated against dangerous schemes. The project is fully buildable, lint-clean, and covered by 30 passing unit tests.

I was able to record a multi-minute screen capture, encrypt and upload it to Sia, generate an expiring share link, and stream it back in a fresh browser tab — confirming the record → encrypt → upload → share → play loop works in practice.

Detail of tasks worked on this month per milestone

Milestone Tasks Pull Request(s)
Onboarding & indexer Vite + React 19 + Tailwind v4 SPA scaffold with WASM init and auth-gate routing; Sia JS SDK integration wrapper (lib/sia.js) for connect, approval, reconnect, upload, and share; onboarding flow with recovery-phrase generation/entry, custom indexer support. #1, #2, #3
Login Returning-user login via stored App Key; phrase re-entry on a new device re-derives the same key #2, #3
Encrypted key storage At-rest App Key encryption with a non-extractable AES-GCM key in IndexedDB (lib/keyStore.js); recovery phrase never stored #2
Recording Camera-only and screen-only modes via MediaRecorder (hooks/useRecorder.js) with runtime codec detection, camera and microphone device selection #4
Upload & share Upload to Sia with user-selected expiry (1h/24h/7d/30d/Never) stored in encrypted object metadata; share-link generation via SDK shareObject() with native expiry #5
Playback Recipient playback page with progressive streaming via MediaSource, a full-buffer blob fallback, and friendly error mapping for expired/invalid links #6
Security & quality Strict production CSP, security headers (frame-ancestors, nosniff), URL scheme validation, and open-redirect protection; 30 passing unit tests, ESLint clean, and lib/ module organization #1, #2, #5, #6

Were there any problems encountered this month?

  • Browser codec variance. MediaRecorder codec support differs across browsers; mitigated by detecting supported MIME types at runtime and falling back to WebM/VP8/Opus.

What will you be working on next month?

  • Implement the no-account recipient playback flow
  • Recording history dashboard with share buttons
  • Picture-in-picture recording mode (camera + screen combined)
  • Regenerate a new share link for any existing recording
  • Manual deletion of recordings
  • Basic account stats from the Sia JS SDK account API
  • User testing and feedback
1 Like