Zero-knowledge, self-destructing document links for India.
Every time you send your Aadhaar or PAN card to a print shop โ via WhatsApp, email, or USB โ it stays on their computer permanently. You have no way to delete it afterward. UIDAI data shows 85,000+ Aadhaar-linked fraud cases per year in India, and a significant share originate here.
bpp_demo.mp4
- Upload your document on your phone โ it's encrypted on-device before anything is sent
- Share a link that expires after N opens or N minutes โ you choose
- Print shop opens the link โ document loads, auto-print fires, link self-destructs
- No copy stays on their machine
Free. No account. Works on any Android phone.
The decryption key lives only in the URL fragment (#key=...). It is never sent to the server, never appears in access logs, never stored in the database. The server only ever sees encrypted .enc blobs. Even with full database and storage access, we cannot read your documents.
Encryption: AES-256-GCM via Web Crypto API
Key derivation (PIN lock): PBKDF2 at 150,000 iterations
Key location: URL fragment โ stripped by browsers before HTTP requests
To verify: pwa/src/lib/crypto.js
| Layer | Choice |
|---|---|
| Frontend | React 18 + Vite 5 + vite-plugin-pwa |
| Encryption | Web Crypto API (AES-256-GCM, key in URL fragment) |
| i18n | i18next โ Hindi default, 22 Indian languages |
| Storage | Supabase Storage (encrypted blobs as {id}.enc) |
| Database | Supabase Postgres with RLS |
| Edge Functions | Supabase Edge Functions (Deno/TypeScript) |
| Hosting | Cloudflare Pages |
| PDF rendering | PDF.js via CDN (client-side only) |
git clone https://github.com/DewashishCodes/bharatprivacyprint.git
cd bharatprivacyprint/pwa
npm installGo to supabase.com and create a new project.
In Supabase SQL Editor, run in order:
supabase/migrations/20260506000000_create_links.sqlsupabase/migrations/20260509000000_consume_link_view.sql
Supabase Dashboard โ Database โ Extensions โ search "pg_cron" โ Enable
Dashboard โ Storage โ New bucket
Name: BharatPrivacyPrint-docs
Visibility: Private (not public)
supabase login
supabase link --project-ref YOUR_PROJECT_REF
supabase functions deploy upload-blob
supabase functions deploy get-blob
supabase functions deploy destroy-link
supabase secrets set CLEANUP_CRON_SECRET=<random-hex>
supabase functions deploy cleanup-blobsThen fill in the two placeholders in 20260509000001_schedule_cleanup.sql (project URL + cleanup secret) and run it in SQL Editor.
cp .env.example pwa/.env
# Edit pwa/.env:
# VITE_SUPABASE_URL=https://your-project.supabase.co
# VITE_SUPABASE_ANON_KEY=your-anon-keycd pwa
npm run dev- Root directory:
pwa - Build command:
npm run build - Build output:
dist - Add
VITE_SUPABASE_URLandVITE_SUPABASE_ANON_KEYin Pages โ Settings โ Environment variables
The consume_link_view Postgres RPC does a single UPDATE ... RETURNING. This eliminates the race condition where two concurrent requests both see view_count < max_views and both succeed. Only one request can "consume" a view slot.
A cleanup-blobs edge function runs every 6 hours via pg_cron. It finds all expired or destroyed links and deletes their .enc files from storage. This prevents orphaned blobs accumulating on the Supabase free tier (500MB limit). Max orphan lifetime: 6 hours.
The upload-blob edge function enforces 10 uploads/hour/IP using an in-memory counter per Deno isolate. For production scale, replace with Upstash Redis.
Issues and PRs are welcome. Key areas where contributions are valuable:
- Translations โ Gujarati, Tamil, Telugu, and Bengali are the highest priority missing translations. Add a file at
pwa/src/locales/{lang}/translation.jsonfollowing the structure inhi/translation.json. - Security review โ the zero-knowledge design is the most important part. Scrutiny of
crypto.js,upload.js, and the Edge Functions is very welcome. - Performance โ target is FCP < 3.0s on 3G, bundle < 150KB gzipped, 5MB PDF encryption < 8s.
AGPL v3.0 โ see LICENSE