A secure, end-to-end encrypted terminal chat application built with Node.js.
No dependencies. No cloud. No registration. Just open a terminal and talk.
- Overview
- Features
- Architecture
- Security Model
- Requirements
- Installation
- Usage
- In-Chat Commands
- Private Messaging
- Admin Controls
- Project Structure
- Known Limitations
- License
Terminal Chat is a self-hosted, LAN/internet chat application that runs entirely in your terminal. It uses TLS to encrypt the transport layer and AES-256-GCM for end-to-end encrypted private messages β the server never sees private message content.
All you need is Node.js and openssl on your PATH.
| Feature | Details |
|---|---|
| π TLS Transport | All traffic is encrypted in transit using a self-signed TLS certificate |
| π E2E Private Messages | Private messages are encrypted client-side with AES-256-GCM; the server only routes the ciphertext |
| π₯ Public Chat | Broadcast messages visible to all connected users |
| π§βπΌ Admin Role | Password-protected admin elevation with /admin command |
| π« Ban System | Admins can ban users by ID; bans persist for the lifetime of the server process |
| β€οΈ Keep-Alive | Server sends __PING__ every 30 seconds; client replies __PONG__ to detect dead connections |
| π‘οΈ DoS Protection | Per-client 1 MB receive buffer limit β oversized payloads drop the connection immediately |
| π¦ Zero Dependencies | Uses only Node.js built-in modules (tls, crypto, readline, fs, child_process) |
| π₯οΈ Background Server | Server runs as a detached background process tracked by a PID file |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β terminal-chat (CLI) β
β bin/terminal-chat.js β
β βββββββββββββββ ββββββββββββββββββββββββ ββββββββββββββββββ β
β β [1] Start β β [2] Connect β β [3] Stop β β
β β Server β β Client β β Server β β
β ββββββββ¬βββββββ ββββββββββββ¬ββββββββββββ βββββββββ¬βββββββββ β
β β β β β
β spawn (detached) spawn (inherit) kill (PID file) β
β β β β
βββββββββββΌβββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββ
β β
βΌ βΌ
lib/server.js lib/client.js
(TLS server) (TLS client)
β β
βββββββββTLSββββββββββ
(encrypted tunnel)
Message flow:
Public message:
client A ββplain textβββΆ server ββbroadcastβββΆ all other clients
Private message (/pm):
client A ββAES-256-GCM ciphertextβββΆ server ββrouteβββΆ client B only
(server never decrypts)
All data travels over TLS 1.2+ using a 2048-bit RSA self-signed certificate generated at install time. The certificate is accepted by clients with rejectUnauthorized: false β traffic is still encrypted, but certificate authenticity is not verified against a CA. For production use, replace the self-signed cert with one issued by a trusted CA.
Each client generates a fresh 32-byte random session key on startup. This key is shared with other clients via key_announce messages routed through the server. Private messages (/pm) are then encrypted client-side with AES-256-GCM before being sent:
Sender: plaintext β AES-256-GCM(key=senderSessionKey) β ciphertext β server β recipient
Recipient: ciphertext β AES-256-GCM decrypt(key=senderSessionKey) β plaintext
The server only ever sees the ciphertext. A compromised server cannot read private messages.
The default admin password is admin123 (stored as a SHA-256 hash). Change it before deploying:
// server.js, line ~25
const ADMIN_PASSWORD_HASH = crypto.createHash('sha256').update('YOUR_PASSWORD').digest('hex');- Node.js >= 18
- OpenSSL available on your system PATH (used to generate the TLS certificate)
To check:
node --version # should be v18.x or higher
openssl version # should print a version stringgit clone https://github.com/your-username/terminal-chat.git
cd terminal-chat
npm install # automatically generates TLS certificate via postinstall.jsnpm install -g .
terminal-chatAfter npm install, you will find lib/server.key and lib/server.crt generated automatically.
Run the CLI entry-point:
# If installed globally:
terminal-chat
# Or directly:
node bin/terminal-chat.jsYou will be presented with:
,_, TERMINAL CHAT π
(O,O)
( )
" "
Select what you want:
[1] Create chat server
[2] Connect to chat
[3] Stop chat server
>
Choose [1] and enter a port (default: 1599).
> 1
Enter port to run chat server (default 1599): 4242
Server started in background on port 4242 (PID 83421).
The server runs detached in the background. You can close the terminal β the server keeps running.
Its PID is saved to ~/.terminal-chat/pids/server-4242.pid.
Choose [2] and provide the server details:
> 2
Enter server IP: 192.168.1.10
Enter server port: 4242
Enter your name: Alice
Connected to server
Welcome Alice! Your ID is [KJ83]
>
Your 4-character ID (e.g. KJ83) is randomly generated each session. Share it with others so they can send you private messages.
Type any message and press Enter to broadcast it to everyone:
> Hello everyone!
<Alice> Hello everyone!
Choose [3] and enter the port of the server to stop:
> 3
Enter port of server to stop (default 1599): 4242
Server on port 4242 (PID 83421) stopped.
Once connected, the following slash-commands are available to all users:
| Command | Description |
|---|---|
/help |
Show all available commands |
/users |
List online users with their IDs and roles |
/pm <ID> <message> |
Send an end-to-end encrypted private message |
/admin |
Prompt for admin password to elevate your role |
/ping |
Check if you're still connected to the server |
/exit or /quit |
Disconnect from the server |
Admin-only commands:
| Command | Description |
|---|---|
/ban <ID> |
Immediately disconnect a user and block future reconnects |
Use /pm followed by the recipient's ID and your message:
> /pm KJ83 Hey Alice, this is a secret message!
[PRIVATE] To KJ83: Hey Alice, this is a secret message!
The recipient sees:
[PRIVATE] From Bob: Hey Alice, this is a secret message!
The message is AES-256-GCM encrypted before leaving your machine. The server routes the ciphertext without ever being able to read it.
To gain admin access:
> /admin
Enter admin password:
> admin123
Admin access granted
Once admin, you can ban a user:
> /users
Online users (3):
- [KJ83] Alice
- [BZ12] Bob (admin)
- [XQ55] Mallory
> /ban XQ55
<announce> User Mallory was banned
Mallory is immediately disconnected and will see You are banned if they try to reconnect with the same ID.
terminal-chat/
βββ bin/
β βββ terminal-chat.js # CLI entry-point; menu, server spawning, client launching
β βββ postinstall.js # Generates TLS key+cert with OpenSSL after npm install
βββ lib/
β βββ server.js # TLS chat server: routing, broadcasting, admin, keep-alive
β βββ client.js # TLS chat client: E2E encryption, readline UI, PING/PONG
β βββ server.key # (generated) TLS private key β keep this secret!
β βββ server.crt # (generated) TLS self-signed certificate
βββ package.json
Note:
server.keyandserver.crtare created bypostinstall.jsand should not be committed to version control. Add them to.gitignore:lib/server.key lib/server.crt
- Self-signed certificate β clients skip CA verification (
rejectUnauthorized: false). Susceptible to MITM attacks on untrusted networks. For production, use a CA-signed certificate. - In-memory ban list β bans are lost when the server restarts.
- Session keys are not authenticated β a malicious server could substitute a user's public key in
key_announcemessages (MITM on E2E keys). For stronger guarantees, add out-of-band key fingerprint verification. - No message history β messages are not stored; joining users see only new messages.
- Single-room β there is no concept of channels or rooms.
MIT Β© Tommy