Skip to content

Nexus Chat

Velle Sinclair edited this page Jul 27, 2026 · 1 revision

Nexus P2P

End-to-end encrypted peer-to-peer chat — text, voice, file transfer and GIFs, with no account and no server holding your messages.

Upstream: velle999/nexus-chat. Packaged for SynapseOS as nexus-chat, and on the ISO.

Running it

nexus-chat

Or Nexus P2P in the start menu, under Internet.

Create a room and you get a room code. Anyone who enters that code joins your room. The launcher also accepts an invite fragment, so a link can open straight into a room:

nexus-chat '#room=...'

Unlike TEPRIS, this runs as an ordinary window with browser chrome intact — it needs URL-hash invite links to be visible and pasteable.

The room code is the password

This is the one thing worth understanding before you use it, because it governs how you share a code.

The encryption key is derived from the room code itself — PBKDF2 at 600,000 iterations (the OWASP figure), run once when you join. There is no separate password and no key exchange. Anyone who has the code can read the room, so send it over a channel you already trust.

Codes are 10 characters — about 50 bits — drawn from crypto.getRandomValues rather than Math.random, so they are not guessable and not biased.

The code never goes on the wire

Rendezvous runs over a public MQTT broker and the public PeerJS cloud for WebRTC signalling. That means the thing peers use to find each other is visible to strangers — so it must not be the code.

It isn't. The public rendezvous id is a SHA-256 hash of the code (first 8 bytes, 16 hex chars); that hash is what becomes the MQTT topic and the PeerJS id. The code stays local: it is only ever the key-derivation input, the thing you copy, and what an invite fragment carries.

This was not always true, and the failure is worth stating plainly because it is a general lesson: the code used to be the topic name. Messages were encrypted, but anyone subscribed to the broker's wildcard could read the code off the envelope and derive the key — so the encryption protected nothing against a passive observer. Encrypting the payload is not enough if the envelope carries the secret.

Media and messages themselves go peer to peer over WebRTC, not through the broker.

Offline behaviour

The app's three third-party JavaScript libraries are vendored into the package rather than loaded from a CDN, and the build fails if any CDN reference survives the rewrite — so the app works with no network beyond the peers themselves. Webfonts are still fetched from Google Fonts and degrade gracefully when they cannot be.

Rolling it

The PKGBUILD pins an upstream commit; bump _commit and pkgrel to roll.

Two values must move in lockstep across every copy: the PBKDF2 iteration count and the room-id derivation. Nothing on the wire records either — there is no protocol version — so a mismatch fails silently and confusingly. A different iteration count connects and then drops every message, because the decrypt error is swallowed. A different derivation puts peers on different topics, so they never see each other at all. If the hosted copy and the packaged copy disagree, peers simply never meet.

The upstream repo also ships two entry points that must be kept identical; the package installs only one, but both are served publicly, so a change to one alone leaves a stale copy live.

See also: TEPRIS, Building and Packaging.

Clone this wiki locally