Skip to content

Repository files navigation

VChat

Censorship-resistant P2P video chat. Connect directly with anyone — no accounts, no servers required. All traffic is disguised as regular HTTPS to bypass Deep Packet Inspection.

See ARCHITECTURE.md for full technical design.

How it works

Direct Connect (no server needed)

  1. Run launch.sh (macOS/Linux) or launch.bat (Windows) from the standalone/ folder
  2. A browser opens at localhost:8043
  3. User A clicks Create Invite → gets a code block
  4. User A sends the code to User B via any messenger (Telegram, WhatsApp, Signal, email, etc.)
  5. User B clicks Join with Invite → pastes the code → gets a response code
  6. User B sends the response code back to User A
  7. User A pastes the response → peer-to-peer video call established!

No port forwarding, no domain names. The code exchange happens through whatever channel the users already have. Video, audio, and text are end-to-end encrypted via WebRTC.

Note: A local HTTP server is required because browsers block WebRTC (STUN/ICE) from file:// URLs. The launcher starts one automatically on localhost:8043.

Server mode (VPS deployment)

For users who prefer a traditional server-based setup:

  1. Both users agree on a secret token and server IP (via phone, email, another messenger)
  2. User A opens the client, enters the token, clicks Create Room
  3. User B opens the client, enters the same token, clicks Join Room
  4. The signaling server matches them by token hash, then clients connect directly via WebRTC

Project structure

vchat/
├── packages/
│   ├── shared/     # Shared TypeScript types and utilities
│   ├── server/     # Node.js signaling + relay server
│   ├── web/        # React + Vite web client
│   └── mobile/     # React Native client (iOS + Android)
└── package.json    # npm workspaces root

Prerequisites

  • Node.js ≥ 22.11
  • npm ≥ 10
  • OpenSSL (for TLS cert generation, server mode only)
  • For mobile:
    • Xcode ≥ 15 (iOS)
    • Android Studio + Android SDK (Android)
    • CocoaPods (gem install cocoapods)
    • JDK 17

Quick start (standalone)

Build the standalone Direct Connect package:

npm install
npm run build:standalone

Output: standalone/ folder containing:

  • index.html — self-contained app (≈ 227 KB)
  • launch.sh / launch.bat / launch.ps1 — platform launchers
  • serve.py — Python HTTP server

Run launch.sh (macOS/Linux) or launch.bat (Windows). Both users need this folder.


Development

1. Install dependencies

npm install

2. Build shared types (required before first run)

npm run build:shared

3. Start dev servers

# Start both server and web client
npm run dev

# Or separately:
npm run dev:server   # Signaling server (https://0.0.0.0:8443)
npm run dev:web      # Web client (https://localhost:5173)

The dev server:

  • Runs on port 8443 with a self-signed TLS cert (auto-generated in packages/server/certs/)
  • Serves a fake "CloudSync Solutions" website on GET / to mimic a real site
  • Accepts WSS connections for signaling

The web client:

  • Runs on port 5173 with Vite's dev SSL
  • Both Direct Connect and Server mode available

4. Mobile development

cd packages/mobile

# iOS
npx pod-install ios        # Install CocoaPods deps
npm run ios                # Build & run on iOS simulator

# Android
npm run android            # Build & run on Android emulator

Note: Camera/mic require a physical device — simulators have limited WebRTC support.


Builds

standalone/ — Direct Connect only

npm run build:standalone

Produces a standalone/ folder with index.html and launcher scripts. Run launch.sh (macOS/Linux) or launch.bat (Windows) to serve the app on localhost:8043. Both users need this folder and any messenger to exchange codes.

Full web client (Direct Connect + Server mode)

npm run build:web
# Output: packages/web/dist/

Includes both Direct Connect and Server mode. Deploy to any static host or serve from a VPS.

Server (for server mode)

npm run build:server
node packages/server/dist/index.js --port 443

The server auto-generates a self-signed cert on first run. To use your own:

node dist/index.js --port 443 --cert /path/to/server.crt --key /path/to/server.key

Direct Connect — how it works

Direct Connect lets two users establish a peer-to-peer video call without any server. It works by exchanging WebRTC signaling data through any existing communication channel.

Technical details

  1. Create Invite: The app creates a WebRTC offer, gathers all ICE candidates, and encodes everything into a single base64 blob (~4 KB of text).
  2. Exchange codes: Users exchange the invite code and response code through any messenger they already have access to.
  3. Connect: Once both sides have exchanged codes, a direct WebRTC connection is established.

What's in the codes

  • WebRTC SDP (Session Description Protocol) — codec info, media capabilities
  • ICE candidates — network addresses for connectivity
  • DTLS fingerprint — for end-to-end encryption verification
  • Stealth level — traffic shaping settings

The codes contain no identifying information. They are one-time use and expire when the browser tab is closed.


Deploying to a VPS (server mode)

1. Provision a VPS

Any VPS provider works (Hetzner, DigitalOcean, Vultr, etc.). Requirements:

  • Static IPv4 address
  • Port 443 open (inbound TCP)
  • Node.js ≥ 22 installed
  • 512 MB RAM is enough

2. Deploy

git clone <your-repo-url> vchat
cd vchat
npm install
npm run build:shared
npm run build:server

sudo node packages/server/dist/index.js --port 443

3. Keep it running with systemd

Create /etc/systemd/system/vchat.service:

[Unit]
Description=VChat Signaling Server
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/opt/vchat
ExecStart=/usr/bin/node packages/server/dist/index.js --port 443
Restart=always
RestartSec=5

NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/opt/vchat/packages/server/certs

[Install]
WantedBy=multi-user.target
sudo systemctl enable vchat
sudo systemctl start vchat

4. Verify it looks legitimate

curl -k https://<server-ip>          # Should show fake website
openssl s_client -connect <server-ip>:443   # Should show valid TLS

Multiple servers

Deploy to several VPS providers in different countries for resilience. If one IP gets blocked, users switch to another. Both users must select the same server.


Stealth modes

The creator selects the stealth level (the joiner inherits it automatically):

Mode What it does Trade-off
Medium (default) Packet padding, timing jitter Good video quality, basic DPI evasion
High Bandwidth cap (1 Mbps), chaff traffic, uniform packet sizes Lower video quality (~480p), stronger DPI evasion

Security notes

  • Video/audio/text are end-to-end encrypted via WebRTC DTLS
  • Text messages are ephemeral — exist only during the active session
  • Direct Connect invite codes contain no identifying information and are one-time use
  • Direct Connect requires no server trust — DTLS fingerprints verify the peer
  • No reliance on third-party tunnel domains that could be blocked or monitored
  • Server stores nothing to disk — all state is in memory
  • Server sees only SHA-256 hashes of tokens, never plaintext
  • Server logs nothing — no IPs, timestamps, or connection records

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages