Files
securebit-chat/README.md
T
lockbitchat 2a7142c722
CodeQL Analysis / Analyze CodeQL (push) Canceled after 0s
Deploy Application / deploy (push) Canceled after 0s
Mirror to Codeberg / mirror (push) Canceled after 0s
Mirror to PrivacyGuides / mirror (push) Canceled after 0s
feat(webrtc): recover a dropped connection without a signalling server; release v5.6.0
A chat no longer dies when the network moves under it. A NAT rebind, a lift, a
Wi-Fi radio parking itself, a phone that dozed: the session repairs its own network
path in place, and the messages typed meanwhile go out when it returns.

Recovery is an ICE restart, which renegotiates only the transport path — the DTLS
handshake, the session keys and the SCTP association carrying the data channel all
sit above ICE and survive it. The renegotiation SDP therefore travels over the
existing end-to-end encrypted, SAS-verified channel: no signalling service enters
the design, and an attacker who cannot already decrypt the session cannot inject a
reconnection. A restart is refused outright unless the DTLS fingerprint in the
incoming SDP matches the live session's, so recovery can never re-point a
conversation at a different peer.

When the path is gone for good the session is ended and its data wiped rather than
left half-alive: with no server there is nothing to re-signal through, and a
conversation whose transport is gone should not leave its plaintext in an open tab.
The two cases where that is already certain are recognised in seconds instead of
being retried for two minutes — a channel that has delivered nothing at all since
the drop cannot carry a renegotiation, and an ICE agent left bound to a network that
no longer exists reports zero candidate pairs on every restart.

Judging liveness was the hard part. Silence is not evidence of death: browsers freeze
backgrounded tabs outright, and a frozen peer answers nothing while being perfectly
healthy. What survives that freeze is ICE consent, which the browser runs in its
network stack rather than on the page's thread — so a connected ICE state means a
silent peer is asleep, and only a degraded one turns an unanswered probe into a
teardown. The grace window before a restart is sized to the browser's own timings:
'disconnected' arrives after ~5s of missed consent responses and is held ~25s before
'failed', and that window exists for self-healing, so restarting at the start of it
broke connections that were about to recover.

Several long-standing bugs surfaced along the way and are fixed here:

- handleHeartbeat() was dispatched to but never defined, so every inbound heartbeat
  threw a TypeError and peer liveness was never observed at all.
- Heartbeats were folded into the 5-minute maintenance cycle instead of running on
  their own timer, far too coarse to notice a dead path.
- ondatachannel can hand over a channel that is already open, so the answering side's
  'open' event had been dispatched before the handler was assigned and never fired,
  leaving that side with no heartbeat, no watchdog and no file-transfer init. The peer
  whose network was fine kept showing "connected" indefinitely because nothing was
  running to notice.
- Answering a heartbeat required the peer to have finished verifying, but the two
  sides confirm a SAS code at different moments; for that whole window one of them
  could not reply and was declared dead on a healthy connection.
- Sending on a channel that was not ready returned in silence: the text stayed in the
  box, nothing was transmitted, and nothing said why.
- The send path gated on navigator.onLine and the offline/online events, which report
  whether an interface exists rather than whether anything is reachable. A tab the OS
  froze misses the 'online' edge, and this side then queued every message forever: one
  tick on everything it sent, while incoming messages kept arriving. Sending is now
  decided by the data channel, and queues drain by polling rather than on an edge, so
  a missed event cannot strand them.
- A false offline modal appeared on a working session, because the offline event was
  taken at face value.

tests/session-recovery.test.mjs covers the state machine, the backoff and its
serialisation, the offline hold, the sleeping-peer discriminator and the identity
check.
2026-08-02 21:16:13 -04:00

9.4 KiB
Raw Blame History

SecureBit.chat

SecureBit.chat

End-to-end encrypted, peer-to-peer chat that runs entirely in your browser.

No accounts. No servers storing your messages. No installation required.

License: MIT Version PWA Encryption

Features · How it works · Security · Quick start · Documentation


SecureBit.chat is a browser-based, peer-to-peer messenger built on WebRTC and the Web Crypto API. Two people establish a direct, end-to-end encrypted channel and verify each other in person — there is no registration, no central server relaying or storing messages, and no metadata account to leak. Everything cryptographic happens locally in the two browsers.

It is designed for people who need a small, auditable, zero-infrastructure way to talk privately: journalists and sources, security researchers, or anyone who simply wants a conversation that leaves nothing behind.

Screenshots

Open a secure channel Encrypted conversation
Open a channel Encrypted chat

Features

** Encryption & verification**

  • ECDH P-384 key agreement with derived per-session keys, AES-256-GCM payloads, and DTLS-protected transport.
  • Interactive Short Authentication String (SAS) verification — you confirm a code out-of-band before the session is trusted, defeating man-in-the-middle attacks.
  • Replay protection, message integrity (HMAC), and a live security report you can open at any time during a call.

** Privacy by design**

  • Direct peer-to-peer connection — messages never touch a SecureBit server.
  • No accounts, no phone numbers, no message history on disk.
  • Optional relay-only mode routes traffic through your own TURN server so your IP is never exposed to the peer.
  • Local key metadata is stored encrypted in IndexedDB; disconnecting cleans up session state.

** Encrypted calls**

  • 1:1 voice and video calls over the same verified peer-to-peer connection — media rides the SAS-verified DTLS-SRTP transport, so calls inherit the session's end-to-end encryption and never traverse a SecureBit server.
  • Adaptive audio: Opus with in-band FEC, DTX and RED redundancy for intelligible speech under 1520% packet loss; audio is prioritised and never throttled by the network controller.
  • Adaptive video: VP9/AV1 single-encoding SVC (H.264/VP8 fallback) that degrades by spatial/temporal layer, with a runtime controller that trims video bitrate on loss/RTT and recovers as the link clears.
  • Live connection-quality indicator (Excellent → Good → Fair → Weak) shown in the call UI, plus in-call mute and video-upgrade controls.

** Messaging**

  • Encrypted voice messages — record in the browser and send over the same end-to-end encrypted transfer channel as files. Audio is captured as PCM/WAV, integrity-protected by a signed hash, and played back inline on the recipient's device without ever touching disk.
  • Code blocks with syntax highlighting and an auto-clearing copy button.
  • View-once and disappearing messages with countdown timers.
  • Unsend (delete for everyone) over the authenticated control channel.
  • WhatsApp-style delivery status (sending → sent → delivered) with offline store-and-forward.

Multiple conversations

  • Run several independent chats at the same time. Every conversation gets its own encrypted session, keys and verification, so two chats can never mix.
  • A side panel lists your open chats with unread badges. Switching is instant, and starting a new chat leaves the others connected.
  • Set your availability (Available, Away, Busy or Invisible) and connected peers can see it. You can also give each chat a private label that is stored only on your device and is never sent to the other side.

** File transfer**

  • Consent-gated, end-to-end encrypted transfers with resumable, per-chunk progress.
  • Strict file-type allowlist; executable and scriptable formats are rejected.

** Progressive Web App**

  • Installable on desktop and mobile, works offline, and ships update notifications.

How it works

SecureBit never sees your conversation. A session is built directly between the two browsers:

   Peer A                         Peer B
     │   1. create encrypted offer   │
     │ ────────────────────────────► │   (shared out-of-band: QR / link / paste)
     │                               │
     │   2. return encrypted answer  │
     │ ◄──────────────────────────── │
     │                               │
     │   3. compare SAS code aloud   │
     │  ✓ both confirm  → verified   │
     │                               │
     │ ═══ end-to-end encrypted ════ │
  1. Peer A creates an offer (sharable as a QR code, link, or text).
  2. Peer B opens it and returns an answer the same way.
  3. Both sides see a SAS code and compare it over a trusted channel (in person, a call you recognize, etc.).
  4. Only after both peers confirm the matching code does the chat unlock. Three failed attempts terminate the session.

Security model

Layer Mechanism
Key agreement ECDH (P-384), per-session derived keys
Transport WebRTC data channel over DTLS
Message encryption AES-256-GCM, end-to-end
Authentication Interactive SAS bound to both peers' DTLS fingerprints
Integrity HMAC + replay protection
Sanitization DOMPurify text-only rendering boundary
Local storage Encrypted key metadata in IndexedDB

A session is not treated as verified until both peers complete the SAS flow. This is the step that protects you against a man-in-the-middle: the code must be compared through a channel an attacker cannot impersonate.

Warning

SecureBit.chat is privacy software, not a guarantee. View-once and disappearing messages are cooperative (not screenshot-proof), and a TURN relay can observe both peers' IPs and traffic timing — though never message contents. See SECURITY_DISCLAIMER.md.

Quick start

Run locally

npm install
npm run build
npm run serve

Open the printed local URL in two browser windows or profiles, then:

  1. Create an offer in the first window.
  2. Transfer it to the second and create an answer.
  3. Return the answer to the first window.
  4. Compare the SAS code out-of-band and enter it on both sides.
  5. Start chatting once both peers are verified.

Install as an app

SecureBit is a PWA — open it in a supported browser and choose Install (or Add to Home Screen on mobile) to run it as a standalone, offline-capable app.

Configuration

TURN / privacy mode

Direct WebRTC connections can reveal IP addresses to the peer. SecureBit supports a relay-only privacy mode:

  • Default keeps standard WebRTC behavior with public STUN.
  • Relay-only sets iceTransportPolicy: "relay" and requires a configured TURN server.
  • STUN alone does not hide IP addresses; public TURN credentials are never bundled.

Configure your own STUN/TURN servers under Advanced network settings, or at deployment time. See doc/CONFIGURATION.md.

File transfer policy

Incoming transfers require explicit consent. Metadata is validated and dangerous names rejected before the prompt appears. Accepted: common raster images, PDF, plain text, and ZIP. Executable/scriptable formats (.exe, .bat, .sh, .js, .msi, .dmg, .jar, .ps1, .vbs, .html, .svg, …) are blocked, and MIME type must agree with the file extension.

Development

Requirements: Node.js 18+ and npm.

npm install
npm test          # run the test suite
npm audit         # check dependencies
npm run build     # build CSS + JS bundles and refresh meta.json
npm run dev       # build and serve locally

Project structure

src/network/      WebRTC connection and session lifecycle
src/transfer/     secure file-transfer implementation
src/crypto/       cryptographic utilities
src/components/   React UI components
src/styles/       component styles
doc/              technical documentation
dist/             built bundles served in production

Documentation

Contributing & responsible use

Issues and pull requests are welcome. SecureBit.chat is intended for lawful, ethical communication only — please read RESPONSIBLE_USE.md before using or contributing.

License

Released under the MIT License.

Built with WebRTC and the Web Crypto API · No servers, no accounts, no compromises.