ciphermesh 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +251 -0
  3. package/README.pt-BR.md +253 -0
  4. package/bin/ciphermesh.js +34 -0
  5. package/docs/ARCHITECTURE.md +1188 -0
  6. package/docs/SETUP.md +305 -0
  7. package/docs/demo.svg +46 -0
  8. package/package.json +87 -0
  9. package/src/client/ChatController.js +2476 -0
  10. package/src/client/Connection.js +129 -0
  11. package/src/client/FileTransfer.js +488 -0
  12. package/src/client/ImagePreview.js +88 -0
  13. package/src/client/UI.js +1830 -0
  14. package/src/client/index.js +231 -0
  15. package/src/crypto/CertPinStore.js +79 -0
  16. package/src/crypto/DeniableEncrypt.js +53 -0
  17. package/src/crypto/DoubleRatchet.js +574 -0
  18. package/src/crypto/Handshake.js +219 -0
  19. package/src/crypto/HistoryStore.js +241 -0
  20. package/src/crypto/IdentityBackup.js +70 -0
  21. package/src/crypto/KeyManager.js +134 -0
  22. package/src/crypto/MessageCrypto.js +181 -0
  23. package/src/crypto/NonceManager.js +72 -0
  24. package/src/crypto/SealedSender.js +58 -0
  25. package/src/crypto/SenderKey.js +204 -0
  26. package/src/crypto/StateManager.js +138 -0
  27. package/src/crypto/TrustStore.js +216 -0
  28. package/src/p2p/Discovery.js +80 -0
  29. package/src/p2p/P2PChatController.js +1856 -0
  30. package/src/p2p/PeerConnectionManager.js +252 -0
  31. package/src/p2p/PeerServer.js +68 -0
  32. package/src/p2p/index.js +219 -0
  33. package/src/protocol/messages.js +138 -0
  34. package/src/protocol/validators.js +175 -0
  35. package/src/server/CertManager.js +173 -0
  36. package/src/server/MessageRouter.js +80 -0
  37. package/src/server/OfflineQueue.js +124 -0
  38. package/src/server/SessionManager.js +296 -0
  39. package/src/server/WebSocketServer.js +632 -0
  40. package/src/server/index.js +89 -0
  41. package/src/shared/AuditLog.js +91 -0
  42. package/src/shared/PluginManager.js +83 -0
  43. package/src/shared/banner.js +271 -0
  44. package/src/shared/commandSuggest.js +59 -0
  45. package/src/shared/config.js +90 -0
  46. package/src/shared/constants.js +126 -0
  47. package/src/shared/coverTraffic.js +34 -0
  48. package/src/shared/dnd.js +60 -0
  49. package/src/shared/emoji.js +17 -0
  50. package/src/shared/fuzzy.js +40 -0
  51. package/src/shared/invite.js +61 -0
  52. package/src/shared/keyArt.js +66 -0
  53. package/src/shared/logger.js +38 -0
  54. package/src/shared/panic.js +38 -0
  55. package/src/shared/prompt.js +31 -0
  56. package/src/shared/terminalGraphics.js +72 -0
  57. package/src/shared/themes.js +36 -0
  58. package/src/shared/voiceNote.js +128 -0
package/docs/SETUP.md ADDED
@@ -0,0 +1,305 @@
1
+ # CipherMesh — Setup and Deploy
2
+
3
+ A complete guide to running the server and connecting clients on the local network.
4
+
5
+ ---
6
+
7
+ ## Option 1: Docker (recommended for the server)
8
+
9
+ ### Requirements
10
+
11
+ - [Docker](https://docs.docker.com/get-docker/) installed
12
+
13
+ ### Bring up the server
14
+
15
+ ```bash
16
+ # Build + start em background
17
+ npm run docker:up
18
+
19
+ # Ou manualmente
20
+ docker compose up -d --build
21
+ ```
22
+
23
+ The server will run on port `3600` (with TLS/`wss://` by default) and be reachable across the entire local network — and, if you use Tailscale, also over the internet (see the section below).
24
+
25
+ ### `ADVERTISE_IP` — show the right IP in the banner (Docker)
26
+
27
+ Inside Docker, the container runs on the Docker bridge (`172.x`) and **cannot see the host's interfaces** (neither the LAN nor `tailscale0`). For that reason, in Docker the banner cannot figure out on its own which address to advertise.
28
+
29
+ The `ADVERTISE_IP` variable solves this — pass one or more host IPs (comma-separated) and the banner will display the correct URLs. Create a `.env` file (already in `.gitignore`) next to `docker-compose.yml`:
30
+
31
+ ```bash
32
+ # .env — IPs do host anunciados no banner (separados por virgula)
33
+ # LAN: ipconfig getifaddr en0 (macOS) / hostname -I (Linux)
34
+ # Tailscale: tailscale ip -4
35
+ ADVERTISE_IP=192.168.1.7,100.73.206.23
36
+ ```
37
+
38
+ The banner then shows:
39
+
40
+ ```
41
+ ╭───────────── SERVER ──────────────╮
42
+ │ Porta 3600 │
43
+ │ Local wss://192.168.1.7:3600 │ ← rede local
44
+ │ Internet wss://100.73.206.23:3600 │ ← Tailscale (fora da rede)
45
+ │ Status ● Online │
46
+ ╰─────────────────────────────────────╯
47
+ ```
48
+
49
+ > `ADVERTISE_IP` only changes **what the banner displays** — it does not restrict who connects. The compose `3600:3600` mapping already exposes the port on **all** of the host's interfaces at once, so the server responds on the LAN and on Tailscale regardless of this.
50
+
51
+ ### View the server logs
52
+
53
+ ```bash
54
+ npm run docker:logs
55
+
56
+ # Ou
57
+ docker compose logs -f
58
+ ```
59
+
60
+ ### Stop the server
61
+
62
+ ```bash
63
+ npm run docker:down
64
+ ```
65
+
66
+ ### Check whether it is running
67
+
68
+ ```bash
69
+ docker ps
70
+ # Deve mostrar: ciphermesh-server
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Option 2: Node.js directly
76
+
77
+ ### Requirements
78
+
79
+ - Node.js >= 20
80
+
81
+ ### Start the server
82
+
83
+ ```bash
84
+ npm run server
85
+ ```
86
+
87
+ The server prints all the LAN IPs and the port.
88
+
89
+ ---
90
+
91
+ ## Connect as a client
92
+
93
+ ### Client requirements
94
+
95
+ - Node.js >= 20
96
+ - Git (to clone the repo)
97
+
98
+ ### Step by step (for you or your friend)
99
+
100
+ ```bash
101
+ # 1. Clonar o repositorio
102
+ git clone https://github.com/FelipeKreulich/secret-chat-lan.git
103
+
104
+ # 2. Entrar na pasta
105
+ cd secret-chat-lan
106
+
107
+ # 3. Instalar dependencias
108
+ npm install
109
+
110
+ # 4. Conectar ao chat
111
+ npm run client
112
+ ```
113
+
114
+ The client will ask for:
115
+ 1. **Nickname** — your name in the chat
116
+ 2. **Server** — the IP of whoever is running the server (e.g., `192.168.1.142:3600`)
117
+
118
+ ### How do you find out the server's IP?
119
+
120
+ When the server starts, it shows the available addresses:
121
+
122
+ ```
123
+ ╭──────────────── SERVER ────────────────╮
124
+ │ Porta 3600 │
125
+ │ Local wss://192.168.1.142:3600 │
126
+ │ Status ● Online │
127
+ ╰──────────────────────────────────────────╯
128
+ ```
129
+
130
+ Your friend types `192.168.1.142:3600` when the client asks for the server (there's no need to type `wss://` — the client completes it on its own and accepts the self-signed certificate automatically).
131
+
132
+ ---
133
+
134
+ ## Typical scenario
135
+
136
+ ```
137
+ Tua maquina (servidor) Maquina do amigo (cliente)
138
+ ┌──────────────────────┐ ┌──────────────────────┐
139
+ │ docker compose up │ │ npm run client │
140
+ │ (ou npm run server) │ │ │
141
+ │ │ Wi-Fi/LAN │ Servidor: │
142
+ │ Porta 3600 aberta ◄├─────────────────┤ 192.168.1.142:3600 │
143
+ │ │ │ │
144
+ │ Tu tambem pode │ │ Tudo criptografado │
145
+ │ rodar npm run client│ │ ponta-a-ponta │
146
+ └──────────────────────┘ └──────────────────────┘
147
+ ```
148
+
149
+ 1. You bring up the server (Docker or Node)
150
+ 2. You open another terminal and run `npm run client` too
151
+ 3. Your friend clones the repo, installs, and runs `npm run client`
152
+ 4. Both pick nicknames and connect to your IP
153
+ 5. E2EE chat up and running
154
+
155
+ ---
156
+
157
+ ## Connecting over the Internet (Tailscale)
158
+
159
+ LAN mode only works with everyone on the **same network**. To talk with someone on **another network** (another house, another city, another country), the simplest way is [Tailscale](https://tailscale.com): a free mesh VPN (based on WireGuard) that creates a "virtual LAN" — the **tailnet** — between your machines. It works even behind CGNAT and double NAT, **without opening a port on the router**.
160
+
161
+ The chat's encryption remains **end-to-end** — Tailscale is only the transport. Even if the Tailscale network were compromised, the content of messages stays protected by E2EE (and there is still identity verification with `/verify`).
162
+
163
+ ### The concept that confuses everyone: the IP belongs to the MACHINE, not something you choose
164
+
165
+ Each device on the tailnet gets its own **fixed IP** in the `100.x` range (CGNAT `100.64.0.0/10`) — this is **that machine's identity** on the network. Consequences:
166
+
167
+ - The server is reachable at the Tailscale IP of the **machine that runs the server**.
168
+ - You **do not "choose"** a `100.x` IP for the server. If you want the server to be `100.a.b.c`, you need to run the server **on that specific machine**.
169
+ - `tailscale status` on a machine lists the 100.x IPs of **each** device (yours and the others'). Your server's is the one on the machine where `docker compose up` / `npm run server` runs.
170
+
171
+ ### 1. Install Tailscale (on both sides)
172
+
173
+ ```bash
174
+ # Linux
175
+ curl -fsSL https://tailscale.com/install.sh | sh
176
+ sudo tailscale up
177
+
178
+ # macOS (app de menu; ou via Homebrew)
179
+ brew install --cask tailscale # depois abra o app e faca login
180
+
181
+ # Windows
182
+ winget install tailscale.tailscale
183
+ ```
184
+
185
+ `tailscale up` (or the app) opens a URL in the browser to log in (Google, GitHub, Microsoft, email...).
186
+
187
+ > **macOS:** the command-line `tailscale` is often **not on the PATH**. If `tailscale ip -4` gives "command not found", use the binary inside the app:
188
+ > ```bash
189
+ > /Applications/Tailscale.app/Contents/MacOS/Tailscale ip -4
190
+ > ```
191
+
192
+ ### 2. Put both machines on the same tailnet
193
+
194
+ Separate accounts **cannot see each other** by default. Choose an option:
195
+
196
+ - **Invite the other person to your tailnet**: [admin console](https://login.tailscale.com/admin/users) → **Users** → **Invite users**. The free plan (Personal) accepts up to ~3 users and 100 devices.
197
+ - **Share only the server machine**: admin console → **Machines** → `...` on the server machine → **Share** — the other person accepts the link and can then see **only** that machine (good for privacy).
198
+
199
+ Confirm that both show up **online** (green dot) in `tailscale status` or in the admin console. If the peer is `offline`, it will **not** be able to connect until it opens Tailscale.
200
+
201
+ ### 3. Find the server's Tailscale IP
202
+
203
+ On the machine that **runs the server**:
204
+
205
+ ```bash
206
+ tailscale ip -4
207
+ # ex: 100.73.206.23
208
+ ```
209
+
210
+ This IP also appears in the server banner with the `Internet` label (outside Docker, the banner detects the Tailscale interface on its own; **inside Docker**, set `ADVERTISE_IP` — see the Docker section above).
211
+
212
+ ### 4. The server responds on the LAN AND on Tailscale at the same time
213
+
214
+ The server does a `bind` on `0.0.0.0:3600`, that is, it listens on **all** of the machine's interfaces simultaneously. You **do not need** to restart or choose the network — the same server is reachable via:
215
+
216
+ - `wss://<IP-LAN>:3600` — for those on the **same local network** (e.g., `wss://192.168.1.7:3600`)
217
+ - `wss://<IP-Tailscale>:3600` — for those **outside the network**, on the tailnet (e.g., `wss://100.73.206.23:3600`)
218
+
219
+ ### 5. Which address to give to whom
220
+
221
+ | Person | Situation | Address you give |
222
+ |---|---|---|
223
+ | Friend on **another network**, with Tailscale | on your tailnet | `<IP-Tailscale>:3600` (e.g., `100.73.206.23:3600`) |
224
+ | Colleague on the **same network**, without Tailscale | same LAN | `<IP-LAN>:3600` (e.g., `192.168.1.7:3600`) |
225
+ | You yourself, on the server machine | localhost | `localhost:3600` |
226
+
227
+ > A peer **without** Tailscale, but on your local network, **does not need** Tailscale — it connects directly via the LAN IP. Tailscale is only needed for those **outside** the network.
228
+
229
+ ### 6. Connect
230
+
231
+ Whoever hosts brings up the server as usual (`docker compose up -d` or `npm run server`). The other person runs `npm run client` and, when asked for the server, provides the IP + port:
232
+
233
+ ```
234
+ Servidor: 100.73.206.23:3600
235
+ ```
236
+
237
+ There's no need to type `wss://` — the client completes it on its own and **accepts the self-signed certificate automatically**. On the first connection the client **pins the certificate fingerprint** (TOFU); if it changes later, the chat displays an alert.
238
+
239
+ **Shortcut — invite with a QR:** whoever hosts can run, inside the chat:
240
+
241
+ ```
242
+ /invite 100.73.206.23:3600
243
+ ```
244
+
245
+ This outputs a `ciphermesh://...` string **with a QR code** that the other person pastes directly into the `Servidor` prompt (it goes straight into the invite's room).
246
+
247
+ ### Tailscale troubleshooting
248
+
249
+ - **`tailscale status`** — lists the tailnet's machines and whether they are online. An `offline` peer does not connect until it opens Tailscale.
250
+ - **`tailscale ping 100.x.y.z`** — tests direct connectivity to the peer (it should respond via DERP or directly).
251
+ - **Host firewall** — allow inbound port `3600`. On macOS: Settings → Network → Firewall. On Windows: `netsh advfirewall firewall add rule name="CipherMesh" dir=in action=allow protocol=TCP localport=3600`.
252
+ - **Docker** — the compose `3600:3600` mapping already exposes the port on all of the host's interfaces (including `tailscale0`), so the connection over the tailnet works; `ADVERTISE_IP` only helps the **banner** show the right IP.
253
+ - **"Connects and drops" / only the LAN works** — confirm that both are on the **same tailnet** (not just installed) and online.
254
+ - **Corporate/hotel Wi-Fi with _client isolation_ (AP isolation)** — devices on the same network cannot see each other; in that case Tailscale (or a cable/another AP) resolves it even while "on the same network".
255
+ - **Self-signed certificate** — normal; the client accepts it on its own and uses E2EE + `/verify` as the real identity protection.
256
+
257
+ ---
258
+
259
+ ## Chat commands
260
+
261
+ Run `/help` in the chat for the **full list**. The main ones:
262
+
263
+ | Command | Description |
264
+ |---------|-----------|
265
+ | `/help` | Full list of commands |
266
+ | `/users` | Online users |
267
+ | `/msg <nick> <texto>` | Private message (DM) |
268
+ | `/invite <ip>:<porta>` | Generate a `ciphermesh://` invite + QR |
269
+ | `/fingerprint [nick]` | Key fingerprint + randomart |
270
+ | `/verify <nick>` | SAS code + QR + randomart to verify identity |
271
+ | `/verify-confirm <nick>` | Mark the peer as verified |
272
+ | `/file <caminho>` | Send a file (the other person accepts with `/accept`) |
273
+ | `/accept` · `/reject` | Accept / decline an offered file |
274
+ | `/img [caminho]` | Render the last received image at high resolution (kitty/iTerm2) |
275
+ | `/join <sala>` · `/rooms` · `/room` | Rooms (channels) |
276
+ | `/backup [caminho]` | Encrypted backup of identity + trust |
277
+ | `/deniable [on\|off]` | Deniable mode (symmetric crypto) |
278
+ | `/ephemeral <tempo>` | Ephemeral messages |
279
+ | `/retention <tempo>` | Purge old local history |
280
+ | `/nick <novo>` | Change nickname (before joining) |
281
+ | `/clear` · `/quit` | Clear the chat / quit |
282
+
283
+ ---
284
+
285
+ ## Troubleshooting
286
+
287
+ ### "Connection refused" / does not connect
288
+
289
+ - Check that the server is running: `docker ps` or check the terminal
290
+ - Check that everyone is on the **same Wi-Fi/LAN** (or the same tailnet, in internet mode)
291
+ - Check that the **firewall** is not blocking port 3600
292
+ - Windows: `Configuracoes > Firewall > Permitir app > Node.js`
293
+ - Or: `netsh advfirewall firewall add rule name="CipherMesh" dir=in action=allow protocol=TCP localport=3600`
294
+ - Test whether the port responds: `curl ws://IP:3600` or open `http://IP:3600` in the browser (it will error out, but if the port connects it is open)
295
+
296
+ ### "npm install" fails on sodium-native
297
+
298
+ `sodium-native` needs to compile C code. Requirements:
299
+ - **Windows**: `npm install --global windows-build-tools` or install the Visual Studio Build Tools
300
+ - **Mac**: `xcode-select --install`
301
+ - **Linux**: `sudo apt install python3 make g++`
302
+
303
+ ### Docker takes a while to build
304
+
305
+ Normal the first time — it has to compile sodium-native inside the container. Subsequent builds use the cache and are fast.
package/docs/demo.svg ADDED
@@ -0,0 +1,46 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 400" font-family="'SF Mono','JetBrains Mono','Fira Code',Menlo,Consolas,monospace" font-size="15">
2
+ <!-- window -->
3
+ <rect x="0" y="0" width="720" height="400" rx="10" fill="#0d0d1a"/>
4
+ <rect x="0" y="0" width="720" height="30" rx="10" fill="#16213e"/>
5
+ <rect x="0" y="20" width="720" height="10" fill="#16213e"/>
6
+ <circle cx="20" cy="15" r="6" fill="#ff5f56"/>
7
+ <circle cx="40" cy="15" r="6" fill="#ffbd2e"/>
8
+ <circle cx="60" cy="15" r="6" fill="#27c93f"/>
9
+ <text x="360" y="20" fill="#8888aa" text-anchor="middle" font-size="13">CipherMesh — End-to-End Encrypted Chat</text>
10
+
11
+ <!-- banner -->
12
+ <text x="24" y="66" font-size="26" font-weight="bold">
13
+ <tspan fill="#00ff9f">Cipher</tspan><tspan fill="#7b2dff">Mesh</tspan>
14
+ <tspan fill="#f72585" font-size="14" font-weight="normal"> ░▒▓ E2EE ▓▒░</tspan>
15
+ </text>
16
+
17
+ <!-- header bar -->
18
+ <rect x="0" y="82" width="720" height="26" fill="#1a1a2e"/>
19
+ <text x="16" y="100">
20
+ <tspan fill="#27c93f">●</tspan><tspan fill="#ffffff" font-weight="bold"> CipherMesh</tspan>
21
+ <tspan fill="#555"> │ </tspan><tspan fill="#ffffff" font-weight="bold">felipe</tspan>
22
+ <tspan fill="#8888aa"> ● 3 online │ </tspan><tspan fill="#00ff9f">E2E</tspan>
23
+ </text>
24
+
25
+ <!-- messages -->
26
+ <text x="16" y="140"><tspan fill="#ffffff">[14:32]</tspan> <tspan>😎</tspan> <tspan fill="#00b8ff" font-weight="bold">ana</tspan><tspan fill="#ffffff">: hey everyone! 👋 let's test this</tspan></text>
27
+ <text x="16" y="166"><tspan fill="#ffffff">[14:32]</tspan> <tspan>🦊</tspan> <tspan fill="#27c93f" font-weight="bold">bob</tspan><tspan fill="#ffffff">: is the crypto actually real? </tspan><tspan fill="#ffd000">`libsodium`</tspan></text>
28
+ <text x="16" y="192"><tspan fill="#8888aa"> ↩ bob: "is the crypto actually real?"</tspan></text>
29
+
30
+ <!-- own message, right aligned -->
31
+ <text x="704" y="218" text-anchor="end"><tspan fill="#ffffff" font-weight="bold">felipe → bob</tspan><tspan fill="#ffffff">: X25519 + XSalsa20-Poly1305 🔒</tspan> <tspan fill="#00ff9f">✓✓</tspan> <tspan fill="#ffffff">[14:33]</tspan></text>
32
+
33
+ <!-- system lines -->
34
+ <text x="16" y="244"><tspan fill="#ffffff">[14:33] * 🔒 Secure channel with ana — E2E established</tspan></text>
35
+ <text x="16" y="270"><tspan fill="#00b8ff">[14:33] Tip: /voice records a voice note · /theme changes colors</tspan></text>
36
+ <text x="16" y="296"><tspan fill="#ffd000">[14:34] ana's ephemeral message burned away ▓▒░·</tspan></text>
37
+
38
+ <!-- status bar -->
39
+ <rect x="0" y="318" width="720" height="24" fill="#16213e"/>
40
+ <text x="16" y="335"><tspan fill="#4cc9f0">#general</tspan> <tspan fill="#8888aa">🔑 A1B2:C3D4:E5F6</tspan> <tspan fill="#7777aa">Ctrl+K commands · Ctrl+E emoji · /help</tspan></text>
41
+
42
+ <!-- input -->
43
+ <rect x="8" y="350" width="704" height="40" rx="6" fill="none" stroke="#27c93f" stroke-width="1.5"/>
44
+ <text x="20" y="375" fill="#ffffff">type a message</text>
45
+ <rect x="140" y="361" width="9" height="18" fill="#ffffff"/>
46
+ </svg>
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "ciphermesh",
3
+ "version": "1.0.0",
4
+ "description": "Secure terminal chat for the local network (LAN) with real end-to-end encryption (E2EE) using libsodium",
5
+ "type": "module",
6
+ "main": "src/client/index.js",
7
+ "bin": {
8
+ "ciphermesh": "bin/ciphermesh.js"
9
+ },
10
+ "files": [
11
+ "bin",
12
+ "src",
13
+ "docs",
14
+ "README.md",
15
+ "README.pt-BR.md",
16
+ "LICENSE"
17
+ ],
18
+ "engines": {
19
+ "node": ">=20.0.0"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/FelipeKreulich/secret-chat-lan.git"
27
+ },
28
+ "homepage": "https://github.com/FelipeKreulich/secret-chat-lan#readme",
29
+ "bugs": {
30
+ "url": "https://github.com/FelipeKreulich/secret-chat-lan/issues"
31
+ },
32
+ "scripts": {
33
+ "server": "node src/server/index.js",
34
+ "client": "node src/client/index.js",
35
+ "p2p": "node src/p2p/index.js",
36
+ "server:dev": "node --watch src/server/index.js",
37
+ "lint": "eslint src/",
38
+ "lint:fix": "eslint src/ --fix",
39
+ "format": "prettier --write \"src/**/*.js\"",
40
+ "format:check": "prettier --check \"src/**/*.js\"",
41
+ "test": "node --test test/*.test.js",
42
+ "test:watch": "node --test --watch test/*.test.js",
43
+ "test:coverage": "node --test --experimental-test-coverage test/*.test.js",
44
+ "validate": "npm run lint && npm run format:check && npm run test",
45
+ "precommit": "npm run validate",
46
+ "prepublishOnly": "npm run validate",
47
+ "docker:build": "docker compose build",
48
+ "docker:up": "docker compose up -d",
49
+ "docker:down": "docker compose down",
50
+ "docker:logs": "docker compose logs -f"
51
+ },
52
+ "dependencies": {
53
+ "blessed": "0.1.81",
54
+ "bonjour-service": "1.4.3",
55
+ "boxen": "8.0.1",
56
+ "chalk": "^5.4.1",
57
+ "figlet": "1.11.2",
58
+ "gradient-string": "3.0.0",
59
+ "jimp": "1.6.1",
60
+ "node-notifier": "10.0.1",
61
+ "qrcode-terminal": "0.12.0",
62
+ "sodium-native": "5.1.0",
63
+ "ws": "8.21.1"
64
+ },
65
+ "devDependencies": {
66
+ "@eslint/js": "10.0.1",
67
+ "eslint": "10.7.0",
68
+ "globals": "^17.7.0",
69
+ "prettier": "^3.9.5"
70
+ },
71
+ "overrides": {
72
+ "uuid": "^11.1.1"
73
+ },
74
+ "keywords": [
75
+ "chat",
76
+ "lan",
77
+ "e2ee",
78
+ "encryption",
79
+ "libsodium",
80
+ "websocket",
81
+ "terminal",
82
+ "cli",
83
+ "security"
84
+ ],
85
+ "author": "Felipe Kreulich <contato.felipe.kreulich@gmail.com> (https://felipe-kreulich.vercel.app)",
86
+ "license": "MIT"
87
+ }