Skip to content

kulharshit21/SecureTalks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

127 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🔐 Privyra · SecureTalks

Private conversations, made simple. A privacy-first E2EE web messenger prototype (repo SecureTalks) with server-blind encrypted storage, identity verification, encrypted attachments, disappearing messages, and opt-in AI tools.

Typing SVG

Next.js React TypeScript Supabase Vitest Libsodium


Solo maintainer · research & architecture · @kulharshit21


Snapshot

Privyra / SecureTalks is a privacy-first encrypted messaging prototype: plaintext stays in an unlocked browser session; Supabase holds ciphertext, AEAD metadata, and encrypted Storage blobs. Attachments (encrypt-then-upload) use the private encrypted-attachments bucket for direct chats — group attach remains incomplete in UI. Disappearing messages combine expires_at, RLS, purge_expired_messages(), and cleanup_expired_messages(). Group chat is a small-team MVP (symmetric epochs — not MLS). Opt-in AI runs only via mistral-ai-assist Edge Function (Next proxy disabled by default); normal send/decrypt never calls AI.

Docs: SECURITY_CLAIMS.md · LIMITATIONS.md · DEPLOYMENT.md · DEMO_SCRIPT.md · docs/THREAT_MODEL.md · docs/SECURITY_MODEL.md · docs/PRODUCTION_ENV_CHECKLIST.md · docs/CRON_CLEANUP.md · docs/privyra-graph-summary.json (curated agent / architecture graph)

⚠️ Timers and server deletion do not stop screenshots, malware, or a compromised device. This project does not claim to be “more secure than WhatsApp” without an independent audit — see LIMITATIONS.md.


Repository on GitHub

Remote: kulharshit21/SecureTalks — description, topics (e.g. privyra, e2ee, supabase, libsodium), and releases are set there.


Architecture

flowchart TB
  subgraph Browser["🔒 Trust boundary — your tab"]
    direction TB
    UI["Next.js App Router UI<br/>shadcn · Tailwind"]
    Vault["Device gate · PIN unlock<br/>private keys in IndexedDB (idb)"]
    Cipher["SessionCipher<br/>X25519 triple DH · XChaCha AEAD envelope"]
    FileAEAD["File symmetric AEAD<br/>random file key · nonce ‖ ciphertext"]
    UI --> Vault
    Vault --> Cipher
    Cipher --> FileAEAD
  end

  subgraph Edge["Supabase — hostile infra assumed"]
    direction TB
    Auth["GoTrue Auth"]
    PG["Postgres + RLS<br/>messages · members · attachments meta"]
    ST["Private bucket<br/>attachments (ciphertext only)"]
    RT["Realtime<br/>typing · inserts"]
  end

  Browser -->|"JWT"| Auth
  Cipher -->|"insert ciphertext row"| PG
  FileAEAD -->|"XHR upload ciphertext"| ST
  PG <-->|"membership-scoped SELECT"| Browser
  ST <-->|"policy via attachments row"| Browser
  PG --> RT
Loading

Encrypt path (high level)

sequenceDiagram
  participant U as User
  participant C as Client crypto
  participant DB as Postgres messages
  participant S as Storage bucket

  U->>C: Plaintext / file bytes
  C->>C: derive outbound DH secrets<br/>wrap UTF8 manifest OR body in AEAD
  C->>DB: ciphertext + nonce + algorithm<br/>associated_data JSON (devices + conversation + ts)
  opt Attachment
    C->>C: random fileKey · AEAD(file)<br/>wrap fileKey with SessionCipher
    C->>S: POST ciphertext blob only
    C->>DB: attachments row (wrapped key + path + mime hint)
  end
Loading

Threat model (honest)

Surface What the server sees What it never sees
messages Ciphertext, nonce, protocol id, bound metadata JSON Plaintext bodies
attachments Storage path, wrapped file key blob (still ciphertext to infra without device secrets), MIME hint Plain files
Client compromise N/A — attacker reads decrypted UX same as user

Read docs/SECURITY_RLS_CHECKLIST.md after migrating. SECURITY_CLAIMS.md records what we do and do not promise.


Stack

Layer Choices
App Next.js 16 · React 19 · Tailwind 4 · shadcn/ui patterns · lucide-react
Auth Supabase Auth (+ SSR @supabase/ssr)
Crypto libsodium-wrappers · session envelope + separate file AEAD domain
Data Postgres RLS · Storage policies · optional pg cron purge

Quick start

git clone https://github.com/kulharshit21/SecureTalks.git
cd SecureTalks
npm ci
cp .env.example .env.local   # fill NEXT_PUBLIC_SUPABASE_* + redirect URLs
npm run dev

Apply SQL from supabase/migrations/ via Supabase CLI or SQL editor (order matters).

Scripts

Command Purpose
npm run dev Local Next dev server
npm run build Production build
npm run lint ESLint
npm run typecheck tsc --noEmit
npm run test Vitest unit/crypto tests
npm run test:e2e Playwright (configure env first)
npm run security:edge-health Probe Edge Functions (cleanup + AI); needs .env.local with anon URL/key
npm run smoke:two-user-chat Optional multi-user smoke script (configure test accounts first)

Auth / device recovery (UI): /forgot-password, /reset-password, /recover-device, /settings/security — see docs/SECURITY_MODEL.md.


Scheduled expiry cleanup

After migrations, public.purge_expired_messages() deletes expired attachment objects then rows. Schedule with Supabase pg_cron or a trusted worker using service_role (already granted EXECUTE in migration). Never ship the service role key to the browser.


Maintainer

Author & sole contributor: kulharshit21


Built with intent · vibe-coded UI · honest crypto boundaries

About

Privyra (SecureTalks): privacy-first E2EE web messenger — libsodium, ciphertext-only Supabase, encrypted attachments, disappearing messages, opt-in AI. Next.js 16 & React 19.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors