fb-messenger-e2ee
v0.1.8
Published
E2EE-only TypeScript/Bun toolkit for Facebook Messenger Noise, Signal Protocol, WA-binary, media, and DGW flows
Downloads
385
Maintainers
Readme
FME - FB Messenger E2EE
FME - FB Messenger E2EE is a TypeScript/Bun toolkit focused on Facebook Messenger E2EE flows built on Noise, WA-binary, protobuf, and the Signal Protocol. It is intentionally scoped to encrypted Messenger operations; for normal/plaintext messaging, use fca-unofficial directly.
fb-messenger-e2ee handles the awkward parts of Messenger E2EE: device registration, persistent cryptographic state, Signal sessions, prekeys, sender keys, encrypted media, and binary transport over a Noise websocket.
Documentation Index
This README gives you the full fast path. The deeper docs split each area into a focused reference:
- Getting Started & Lifecycle: Installation,
FBClientinitialization, and connection lifecycles (connectvsconnectE2EE). - Cryptography & Key Maintenance:
DeviceStore, prekey maintenance, and Group Sender-Key Distribution Messages (SKDM). - Messaging API: Sending E2EE text messages, reactions, edits, typing events, and revokes.
- Media Handling: Encrypting and sending images, videos, audio, and documents over E2EE.
- Event Handling: Listening to real-time
e2ee_message,reaction,receipt, and error events. - Internal Architecture: Internal modules and receive/send data paths.
Key Features
- Native E2EE path: Signal Protocol sessions, prekeys, sender keys, Noise socket frames, and WA-binary nodes for encrypted Messenger chats.
- Group sender-key support: Group
skmsgdecrypt/encrypt plus participant fanout of sender-key distribution messages (skdm). - Device persistence: JSON-backed
DeviceStorekeeps Noise keys, Signal identity, sessions, prekeys, signed prekeys, and sender keys across restarts. - Automatic prekey maintenance: Replenishes server-side one-time prekeys without deleting or re-registering the E2EE device.
- Typed E2EE events: Catch-all and typed event subscriptions for E2EE messages, receipts, reactions, errors, and raw frames.
- Encrypted media helpers: Send images, videos, audio, documents, and multi-file batches through the E2EE path.
- DGW support: Optional Direct Gateway / LightSpeed socket helpers.
Tech Stack
- Runtime: Bun / Node-compatible APIs
- Language: TypeScript
- Build output: ESM and CommonJS bundles via
tsup - Encryption: @signalapp/libsignal-client
- Protocol: ProtobufJS + manual WA-binary/protobuf encoders
- Transport: WebSocket + Messenger E2EE Noise frames
- Auth bootstrap bridge: fca-unofficial is used internally only for appState login/CAT bootstrap.
Getting Started
1. Install
npm install fb-messenger-e2ee
# or
bun add fb-messenger-e2ee2. Import
ESM / TypeScript / modern Node.js:
import { FBClient } from "fb-messenger-e2ee";CommonJS:
const { FBClient } = require("fb-messenger-e2ee");3. Connect and Send an E2EE Message
import { FBClient } from "fb-messenger-e2ee";
const client = new FBClient({
// Path to Facebook appState JSON. This contains active login cookies/session data.
appStatePath: "./appstate.json",
sessionStorePath: "./session.json",
platform: "facebook",
});
const { userId } = await client.connect();
// Keep this file. It is the registered E2EE device identity and Signal state.
await client.connectE2EE("./device-store.json", userId);
client.onEvent((event) => {
if (event.type === "e2ee_connected") {
console.log("E2EE stream is ready");
}
if (event.type === "e2ee_message") {
console.log(`[E2EE] ${event.data.threadId} ${event.data.senderJid}: ${event.data.text}`);
}
if (event.type === "error") {
console.error("Client error:", event.data.message);
}
});
await client.sendMessage({
threadId: "1234567890", // user ID, *.@msgr JID, or group JID
text: "Hello from the secure side!",
});The normal lifecycle is:
connect()authenticates enough of the Facebook session to obtain the E2EE bootstrap material.connectE2EE(deviceStorePath, userId)starts the encrypted Noise/Signal stream.- Send messages or listen for E2EE events.
disconnect()when the process should shut down cleanly.
Device Store & Key Maintenance
connectE2EE(deviceStorePath, userId) loads or creates a persistent device store. Do not delete it as a normal recovery step.
The device store contains long-lived E2EE identity and cryptographic state:
| Field | Purpose |
|---|---|
| noise_key_priv | Noise handshake private key |
| identity_key_priv | Signal identity private key |
| registration_id | Signal registration ID |
| adv_secret_key | Messenger/WA companion secret |
| facebook_uuid | ICDC device UUID |
| jid_user, jid_device | Registered Messenger E2EE device JID |
| pre_keys | Local one-time prekey records |
| signed_pre_keys / signed_pre_key_id | Signed prekey records |
| sessions | Signal sessions with other devices |
| sender_keys | Group sender-key state from SKDM |
Deleting the store generates a new Noise key, Signal identity, registration ID, facebook_uuid, and device registration. Keeping it lets the same registered E2EE device continue using existing sessions and sender keys.
Prekey maintenance is automatic and does not require deleting or re-registering the E2EE device:
| Env | Default | Purpose |
|---|---:|---|
| FB_E2EE_PREKEY_SYNC_INTERVAL_MS | 1800000 | Periodic prekey check interval in milliseconds. Set 0 to disable. |
| FB_E2EE_PREKEY_MIN_COUNT | 5 | Upload more prekeys when server count falls below this. |
| FB_E2EE_PREKEY_UPLOAD_COUNT | 50 | Number of fresh one-time prekeys to upload per refill. |
Group decrypt note: if local sender_keys for a group/sender are truly missing, the client cannot derive that key locally. On retryable decrypt failures it sends an E2EE retry receipt to request a resend/SKDM from the sender/server. The send path also keeps a short in-memory retry cache so incoming receipt type="retry" requests for recently sent messages can be re-encrypted directly to the requesting device.
Event Identity Model
E2EE events separate the conversation identity from the sender device identity:
threadId: Stable conversation ID. For DMs this is the bare Facebook user ID; for groups it is the group JID.chatJid: Canonical E2EE chat JID. For DMs this isuser.0@msgr; for groups it is[email protected].senderJid: Device-specific sender JID such asuser.160@msgr.senderDeviceId: Numeric Messenger E2EE device ID when available.kind: Normalized content kind (text,image,reaction,edit, etc.). Empty optional fields are omitted from the event payload.
Project Structure
src/
├── actions/ # Public operation implementations grouped by domain
│ ├── media/ # Media send/download actions
│ ├── messaging/ # Message, reaction, typing, read, and listen actions
│ ├── thread/ # Thread/group management actions
│ └── user/ # User lookup and friend-list actions
├── config/ # Environment helpers
├── controllers/ # Runtime orchestration, socket handlers, event mapping
├── core/ # Public FBClient facade and ActionContext contract
├── e2ee/
│ ├── application/ # E2EEClient, retry/prekey/cache/fanout runtime helpers
│ ├── facebook/ # Facebook-specific SKMSG/SKDM/ICDC helpers
│ ├── media/ # Media crypto/upload primitives
│ ├── message/ # Protobuf writer/builders/codecs/schemas
│ ├── signal/ # Signal sessions, prekeys, sender keys
│ ├── store/ # DeviceStore plus JSON migration/repository
│ └── transport/ # Noise, WA-binary, DGW sockets
├── models/ # TypeScript interfaces and domain models
├── repositories/ # Session persistence
├── services/ # Auth/CAT bridge, gateway, ICDC, E2EE, media, thread services
├── types/ # Advanced utility types and external module declarations
└── utils/ # Logger and conversion helpersThe high-level flow is:
FBClient
-> ClientController
-> ActionContext + domain actions
-> services/controllers
-> e2ee internals
-> Messenger Noise/DGW/FCA gatewaysBuild & Development
Install dependencies:
npm install
# or
bun installGenerate ESM and CommonJS bundles in dist/:
npm run build
# or
bun run buildRun TypeScript checking:
npm run typecheckRun the Jest test suite:
npm test -- --runInBandRun the manual E2EE echo script:
bun run tests/script/echo-e2ee.tsThe echo script is intended for manual account/session validation. It requires usable Facebook appState/session inputs and may keep the process alive while listening.
Package Contents
The npm package publishes:
dist/: ESM, CommonJS, source maps, and declaration files.proto/: Protocol definitions and protobuf writer support files.README.mdanddocs/: GitHub/npm documentation.LICENSE: AGPL-3.0-or-later license text.
License
Licensed under the GNU Affero General Public License v3.0.
