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.
- package/LICENSE +21 -0
- package/README.md +251 -0
- package/README.pt-BR.md +253 -0
- package/bin/ciphermesh.js +34 -0
- package/docs/ARCHITECTURE.md +1188 -0
- package/docs/SETUP.md +305 -0
- package/docs/demo.svg +46 -0
- package/package.json +87 -0
- package/src/client/ChatController.js +2476 -0
- package/src/client/Connection.js +129 -0
- package/src/client/FileTransfer.js +488 -0
- package/src/client/ImagePreview.js +88 -0
- package/src/client/UI.js +1830 -0
- package/src/client/index.js +231 -0
- package/src/crypto/CertPinStore.js +79 -0
- package/src/crypto/DeniableEncrypt.js +53 -0
- package/src/crypto/DoubleRatchet.js +574 -0
- package/src/crypto/Handshake.js +219 -0
- package/src/crypto/HistoryStore.js +241 -0
- package/src/crypto/IdentityBackup.js +70 -0
- package/src/crypto/KeyManager.js +134 -0
- package/src/crypto/MessageCrypto.js +181 -0
- package/src/crypto/NonceManager.js +72 -0
- package/src/crypto/SealedSender.js +58 -0
- package/src/crypto/SenderKey.js +204 -0
- package/src/crypto/StateManager.js +138 -0
- package/src/crypto/TrustStore.js +216 -0
- package/src/p2p/Discovery.js +80 -0
- package/src/p2p/P2PChatController.js +1856 -0
- package/src/p2p/PeerConnectionManager.js +252 -0
- package/src/p2p/PeerServer.js +68 -0
- package/src/p2p/index.js +219 -0
- package/src/protocol/messages.js +138 -0
- package/src/protocol/validators.js +175 -0
- package/src/server/CertManager.js +173 -0
- package/src/server/MessageRouter.js +80 -0
- package/src/server/OfflineQueue.js +124 -0
- package/src/server/SessionManager.js +296 -0
- package/src/server/WebSocketServer.js +632 -0
- package/src/server/index.js +89 -0
- package/src/shared/AuditLog.js +91 -0
- package/src/shared/PluginManager.js +83 -0
- package/src/shared/banner.js +271 -0
- package/src/shared/commandSuggest.js +59 -0
- package/src/shared/config.js +90 -0
- package/src/shared/constants.js +126 -0
- package/src/shared/coverTraffic.js +34 -0
- package/src/shared/dnd.js +60 -0
- package/src/shared/emoji.js +17 -0
- package/src/shared/fuzzy.js +40 -0
- package/src/shared/invite.js +61 -0
- package/src/shared/keyArt.js +66 -0
- package/src/shared/logger.js +38 -0
- package/src/shared/panic.js +38 -0
- package/src/shared/prompt.js +31 -0
- package/src/shared/terminalGraphics.js +72 -0
- package/src/shared/themes.js +36 -0
- 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
|
+
}
|