whalibmob 2.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/README.md ADDED
@@ -0,0 +1,379 @@
1
+ # whalibmob
2
+
3
+ A pure JavaScript Node.js library and CLI for WhatsApp. Operates as a
4
+ mobile iOS client with full Signal Protocol end-to-end encryption, SenderKey
5
+ group messaging, multi-device fanout, persistent sessions, and automatic
6
+ reconnection.
7
+
8
+ ---
9
+
10
+ > **⚠️ IMPORTANT — You need a brand-new phone number and a brand-new SIM card
11
+ > dedicated to WhatsApp for this library to work for you.** Using an existing
12
+ > WhatsApp account that is already active on a real phone will cause
13
+ > WhatsApp to ban or revoke the session. Register a fresh number that has
14
+ > never been used with WhatsApp before.
15
+
16
+ ---
17
+
18
+ ## Features
19
+
20
+ - **Mobile iOS fingerprint** — authentic iOS device headers; behaves like
21
+ WhatsApp on an iPhone
22
+ - **Signal Protocol E2E encryption** — X3DH session setup, Double Ratchet
23
+ for 1-to-1 messages
24
+ - **SenderKey group encryption** — efficient group messaging with chain-key
25
+ advance and SKDM distribution
26
+ - **Multi-device fanout** — messages delivered to all linked devices of each
27
+ recipient via usync device query
28
+ - **All media types** — images, video, audio, voice notes (PTT), documents,
29
+ stickers; AES-256-CBC + HKDF-SHA256 encryption, uploaded to WhatsApp CDN
30
+ - **Text, reactions, extended text** — full message type coverage
31
+ - **Participant hash (phash)** — SHA-256 participant-list validation sent
32
+ with every multi-device and group message
33
+ - **deviceSentMessage** — own linked devices (tablet, secondary phone) receive
34
+ a proper copy-sent wrapper so they show the message as sent
35
+ - **senderKeyMap** — SKDM is sent to each device only once; subsequent group
36
+ messages skip SKDM entirely for devices that already have the key
37
+ - **Automatic reconnection** — exponential backoff (1 s → 2 → 4 → 8 → 15 → 30 s)
38
+ - **Pre-key replenishment** — automatic upload when supply drops below 20
39
+ - **Persistent sessions** — JSON files on disk; no re-registration after restart
40
+ - **Auth confirmation** — waits for server `<success>` before declaring the
41
+ connection open; handles `<failure>` (session revoked / account banned)
42
+ - **Professional `wa` CLI** — yowsup-style interface for registration, sending,
43
+ listening, and interactive chat
44
+
45
+ ---
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ cd tools/whalibmob
51
+ npm install
52
+ npm link # makes `wa` available globally
53
+ ```
54
+
55
+ Requires **Node.js 18** or higher.
56
+
57
+ ---
58
+
59
+ ## CLI Usage
60
+
61
+ ### Check if a number is registered
62
+
63
+ ```bash
64
+ wa registration --check 919634847671
65
+ ```
66
+
67
+ ### Request a verification code
68
+
69
+ ```bash
70
+ # via SMS (default)
71
+ wa registration --request-code 919634847671
72
+
73
+ # via voice call
74
+ wa registration --request-code 919634847671 --method voice
75
+
76
+ # via backup WhatsApp account (wa_old)
77
+ wa registration --request-code 919634847671 --method wa_old
78
+ ```
79
+
80
+ ### Register with the received code
81
+
82
+ ```bash
83
+ wa registration --register 919634847671 --code 123456
84
+ ```
85
+
86
+ ### Connect and enter an interactive shell
87
+
88
+ ```bash
89
+ wa connect 919634847671
90
+ ```
91
+
92
+ Interactive commands at the `wa>` prompt:
93
+
94
+ ```
95
+ /send <jid> <text> Send a text message
96
+ /presence Set presence to available
97
+ /presence away Set presence to unavailable
98
+ /quit Disconnect and exit
99
+ ```
100
+
101
+ ### Send messages
102
+
103
+ ```bash
104
+ # Text
105
+ wa send 919634847671 --to 911234567890@s.whatsapp.net --text "Hello!"
106
+
107
+ # Image with caption
108
+ wa send 919634847671 --to 911234567890@s.whatsapp.net --image ./photo.jpg --caption "Look at this"
109
+
110
+ # Video
111
+ wa send 919634847671 --to 911234567890@s.whatsapp.net --video ./clip.mp4
112
+
113
+ # Voice note (PTT)
114
+ wa send 919634847671 --to 911234567890@s.whatsapp.net --ptt ./voice.ogg
115
+
116
+ # Audio file
117
+ wa send 919634847671 --to 911234567890@s.whatsapp.net --audio ./song.mp3
118
+
119
+ # Document
120
+ wa send 919634847671 --to 911234567890@s.whatsapp.net --document ./report.pdf
121
+
122
+ # Sticker
123
+ wa send 919634847671 --to 911234567890@s.whatsapp.net --sticker ./sticker.webp
124
+
125
+ # Emoji reaction
126
+ wa send 919634847671 --to 911234567890@s.whatsapp.net --reaction 👍 --msg-id 3EB0ABCDEF123456
127
+
128
+ # Group message
129
+ wa send 919634847671 --to 120363000000000000@g.us --text "Hi everyone!"
130
+ ```
131
+
132
+ ### Listen for incoming messages
133
+
134
+ ```bash
135
+ wa listen 919634847671
136
+ ```
137
+
138
+ ### Print version
139
+
140
+ ```bash
141
+ wa version
142
+ ```
143
+
144
+ ### Full options reference
145
+
146
+ | Flag | Description |
147
+ |---|---|
148
+ | `--session <dir>` | Session directory (default: `~/.waSession`) |
149
+ | `--method sms\|voice\|wa_old` | Verification code delivery method |
150
+ | `--code <code>` | Verification code |
151
+ | `--to <jid>` | Recipient JID (`phone@s.whatsapp.net` or `groupid@g.us`) |
152
+ | `--text <msg>` | Text message body |
153
+ | `--caption <text>` | Caption for media messages |
154
+ | `--reaction <emoji>` | Emoji to send as a reaction |
155
+ | `--msg-id <id>` | Message ID to react to (required with `--reaction`) |
156
+
157
+ ---
158
+
159
+ ## Library Usage
160
+
161
+ ### Connect and send messages
162
+
163
+ ```javascript
164
+ const { WhalibmobClient } = require('whalibmob');
165
+
166
+ const client = new WhalibmobClient({ sessionDir: '/path/to/sessions' });
167
+
168
+ client.on('connected', async () => {
169
+ // Text
170
+ await client.sendText('919876543210@s.whatsapp.net', 'Hello!');
171
+
172
+ // Image
173
+ await client.sendImage('919876543210@s.whatsapp.net', '/path/to/photo.jpg', {
174
+ caption: 'My photo'
175
+ });
176
+
177
+ // Image from Buffer
178
+ const buf = require('fs').readFileSync('/path/to/photo.jpg');
179
+ await client.sendImage('919876543210@s.whatsapp.net', buf, { caption: 'From buffer' });
180
+
181
+ // Voice note
182
+ await client.sendAudio('919876543210@s.whatsapp.net', '/path/to/voice.ogg', {
183
+ ptt: true,
184
+ seconds: 12
185
+ });
186
+
187
+ // Document
188
+ await client.sendDocument('919876543210@s.whatsapp.net', '/path/to/file.pdf', {
189
+ fileName: 'report.pdf',
190
+ mimetype: 'application/pdf'
191
+ });
192
+
193
+ // Reaction
194
+ await client.sendReaction('919876543210@s.whatsapp.net', '3EB0ABC123', '👍');
195
+
196
+ // Group message
197
+ await client.sendText('120363000000000000@g.us', 'Hi group!');
198
+ });
199
+
200
+ client.on('message', (msg) => {
201
+ console.log('From:', msg.from, '|', msg.text);
202
+ });
203
+
204
+ client.on('auth_failure', ({ reason }) => {
205
+ console.error('Session revoked by WhatsApp:', reason);
206
+ // reason values: '401', '403', 'not_authorized', 'device_removed', etc.
207
+ });
208
+
209
+ client.on('close', () => console.log('Disconnected'));
210
+ client.on('error', (err) => console.error(err));
211
+
212
+ await client.init('919634847671');
213
+ ```
214
+
215
+ ### Registration (programmatic)
216
+
217
+ ```javascript
218
+ const {
219
+ createNewStore,
220
+ saveStore,
221
+ loadStore,
222
+ checkIfRegistered,
223
+ requestSmsCode,
224
+ verifyCode
225
+ } = require('whalibmob');
226
+
227
+ const storePath = '/path/to/sessions/919634847671.json';
228
+
229
+ // Create or load a session store
230
+ let store = loadStore(storePath) || createNewStore('919634847671');
231
+
232
+ // Check if already registered
233
+ const status = await checkIfRegistered(store);
234
+ console.log(status.status); // "ok" if registered
235
+
236
+ // Request verification code — methods: "sms", "voice", "wa_old"
237
+ const res = await requestSmsCode(store, 'sms');
238
+ console.log(res.status); // "sent" on success
239
+
240
+ // Verify the received code and save session
241
+ const reg = await verifyCode(store, '123456');
242
+ if (reg.status === 'ok') {
243
+ saveStore(store, storePath);
244
+ console.log('Registered!');
245
+ }
246
+ ```
247
+
248
+ ---
249
+
250
+ ## Events
251
+
252
+ | Event | Payload | Description |
253
+ |---|---|---|
254
+ | `connected` | — | Server confirmed `<success>`, session is live |
255
+ | `close` | — | Connection closed |
256
+ | `disconnected` | — | TCP connection dropped (reconnect scheduled) |
257
+ | `reconnecting` | `{ delay, attempt }` | About to reconnect after backoff delay |
258
+ | `reconnected` | — | Reconnection succeeded |
259
+ | `auth_failure` | `{ reason, node }` | Server sent `<failure>` — session revoked or account banned |
260
+ | `error` | `Error` | Non-fatal error occurred |
261
+ | `message` | `{ id, from, participant, ts, text?, plaintext?, isGroup? }` | Incoming message (plaintext is a Buffer) |
262
+ | `receipt` | `{ id, from, type }` | Delivery or read receipt |
263
+ | `presence` | `{ from, available }` | Contact came online / went offline |
264
+ | `call` | `{ from, node }` | Incoming call (auto-rejected by the library) |
265
+ | `notification` | `{ type, attrs, node }` | Raw server notification |
266
+ | `decrypt_error` | `{ id, from, err }` | Decryption failed; retry request sent automatically |
267
+ | `media_conn` | `{ hosts, auth }` | Media upload server connection ready |
268
+ | `session_refresh` | `{ node }` | Server sent a late `<success>` (re-auth flow) |
269
+ | `stream_error` | `{ reason }` | Server-side stream error |
270
+
271
+ ---
272
+
273
+ ## Session Files
274
+
275
+ Sessions are stored as JSON in the session directory (default `~/.waSession`):
276
+
277
+ ```
278
+ ~/.waSession/919634847671.json # WhatsApp credentials and keys
279
+ ~/.waSession/919634847671.signal.json # Signal Protocol session state
280
+ ~/.waSession/919634847671.sk.json # SenderKey group state + SKDM map
281
+ ```
282
+
283
+ Once registered, sessions persist across restarts. Re-registration is only
284
+ required if WhatsApp revokes the session (you will receive an `auth_failure`
285
+ event with reason `401` or `not_authorized`).
286
+
287
+ ---
288
+
289
+ ## Signal Protocol
290
+
291
+ End-to-end encryption follows the Signal Protocol spec:
292
+
293
+ 1. On first connection, pre-keys are generated and uploaded to WhatsApp.
294
+ 2. When contacting a new recipient, the library fetches their pre-key bundle
295
+ and runs X3DH to establish a session.
296
+ 3. All subsequent messages use the Double Ratchet algorithm.
297
+ 4. Pre-keys are automatically replenished when supply drops below 20.
298
+ 5. Session state is persisted to disk between restarts.
299
+
300
+ ---
301
+
302
+ ## Group Messaging (SenderKey)
303
+
304
+ Group messages use the SenderKey protocol for efficient delivery:
305
+
306
+ 1. Each sender generates a SenderKey (signing key pair + chain key).
307
+ 2. On first group message, a SenderKey Distribution Message (SKDM) is
308
+ encrypted individually for every device of every group member and sent.
309
+ 3. Subsequent messages are encrypted once with the SenderKey and broadcast
310
+ — no per-member re-encryption needed.
311
+ 4. The library tracks which devices have already received the SKDM (persisted
312
+ in `.sk.json`) and skips them on subsequent messages.
313
+ 5. The chain key advances with each message (HMAC-SHA256).
314
+ 6. Out-of-order message decryption is supported via cached message keys.
315
+
316
+ ---
317
+
318
+ ## Multi-Device
319
+
320
+ The library fully supports WhatsApp's multi-device architecture:
321
+
322
+ - Device lists are fetched via usync queries.
323
+ - Signal sessions are established for each linked device.
324
+ - All outgoing DMs are fanned out to every device of every recipient as well
325
+ as the sender's own linked devices (tablet, secondary phone, etc.).
326
+ - Own linked devices receive a `deviceSentMessage` wrapper so they display
327
+ the message as sent (not received).
328
+ - All multi-device stanzas include a `phash` (SHA-256 participant hash) so
329
+ the server can validate the participant list.
330
+ - SKDM distribution in groups covers all member devices.
331
+
332
+ ---
333
+
334
+ ## Noise Handshake & Auth
335
+
336
+ The transport uses **Noise_XX_25519_AESGCM_SHA256**:
337
+
338
+ 1. TCP connection to `g.whatsapp.net:443`.
339
+ 2. Client sends `ClientHello` with ephemeral X25519 public key.
340
+ 3. Server replies with `ServerHello` (ephemeral + encrypted static + payload).
341
+ 4. Three Diffie-Hellman steps (EE, SE, SS) derive the session keys.
342
+ 5. Client sends `ClientFinish` (encrypted static + encrypted payload).
343
+ 6. **Library waits for the server's `<success>` or `<failure>` node.**
344
+ 7. Only after `<success>` is the channel opened and the `connected` event
345
+ emitted. A `<failure>` rejects with an `auth_failure` event.
346
+
347
+ ---
348
+
349
+ ## Automatic Reconnection
350
+
351
+ The client reconnects on disconnect with exponential backoff:
352
+
353
+ | Attempt | Delay |
354
+ |---|---|
355
+ | 1 | 1 s |
356
+ | 2 | 2 s |
357
+ | 3 | 4 s |
358
+ | 4 | 8 s |
359
+ | 5 | 15 s |
360
+ | 6+ | 30 s |
361
+
362
+ ---
363
+
364
+ ## Media Encryption
365
+
366
+ Media files use WhatsApp's standard encryption scheme:
367
+
368
+ 1. A random 32-byte media key is generated.
369
+ 2. HKDF-SHA256 expands it to produce the IV, cipher key, and MAC key.
370
+ 3. The file is encrypted with AES-256-CBC.
371
+ 4. A 10-byte HMAC-SHA256 MAC is appended.
372
+ 5. The encrypted ciphertext is uploaded to WhatsApp's CDN.
373
+ 6. The media key and URL are sent in the message envelope.
374
+
375
+ ---
376
+
377
+ ## License
378
+
379
+ MIT