137 lines
5.5 KiB
Markdown
137 lines
5.5 KiB
Markdown
# @vojo/widget-whatsapp
|
|
|
|
Vojo WhatsApp bridge management widget — mounts inside `/bots/whatsapp`
|
|
in the Vojo client. Drives the mautrix-whatsapp bridge bot
|
|
(`@whatsappbot:vojo.chat`) by sending bridgev2 commands in the control DM
|
|
and rendering the bot's text replies into a typed login flow.
|
|
|
|
This is **not** a WhatsApp client — Vojo continues using the Matrix room
|
|
the bridge writes to. The widget is a panel that handles authentication
|
|
(QR scan or pairing code) and surfaces session status.
|
|
|
|
## Layout
|
|
|
|
```
|
|
src/
|
|
├── bootstrap.ts Parse URL params the host appends (mirrors BotWidgetEmbed.ts)
|
|
├── widget-api.ts Inline matrix-widget-api postMessage transport (no SDK)
|
|
├── App.tsx UI: login forms, QR / pairing-code panels, transcript pane
|
|
├── main.tsx Entry: init bootstrap, render App or diagnostic
|
|
├── styles.css Theme-aware CSS (Vojo Dawn palette)
|
|
├── state.ts Login state machine + hydrate-from-timeline
|
|
├── i18n/ Russian primary + English fallback
|
|
└── bridge-protocol/
|
|
├── types.ts LoginEvent discriminated union
|
|
├── parser.ts Dispatch shim
|
|
└── dialects/
|
|
└── bridgev2_v0264.ts Regex table pinned to mautrix-whatsapp v0.26.4
|
|
```
|
|
|
|
## Login flows
|
|
|
|
WhatsApp's mautrix bridge ships TWO login flows (see
|
|
`pkg/connector/login.go::GetLoginFlows`):
|
|
|
|
1. **QR** (`!wa login qr`) — bridge emits a rotating `m.image` whose body
|
|
is the raw whatsmeow handshake payload (`<ref>,<noise>,<identity>,<adv>`,
|
|
four base64 fields). The widget renders it as a QR matrix client-side.
|
|
Whatsmeow `qrIntervals = [60s, 20s, 20s, 20s, 20s, 20s]` — first QR
|
|
lasts 60 seconds, then five rotations of 20 seconds each. Total active
|
|
window: 2 minutes 40 seconds. Each rotation arrives as an `m.replace`
|
|
edit of the original event; the state machine matches on the original
|
|
id and repaints the matrix.
|
|
|
|
2. **Pairing code** (`!wa login phone`) — alternative for users whose
|
|
camera doesn't work or who prefer typing. The user enters a phone
|
|
number; the bridge replies with two notices:
|
|
- `Input the pairing code in the WhatsApp mobile app to log in`
|
|
- The 8-character code itself (`XXXX-XXXX`, custom base32 alphabet).
|
|
The widget renders the code prominently and the user enters it in
|
|
WhatsApp → Settings → Linked devices → Link with phone number.
|
|
|
|
There is **no 2FA cloud-password step** — multidevice handshake is
|
|
single-factor. The state machine has no `awaiting_password` arm.
|
|
|
|
## Capability contract
|
|
|
|
The widget requests EXACTLY this set (matches the host's
|
|
`BotWidgetDriver.getBotWidgetCapabilities`):
|
|
|
|
```
|
|
org.matrix.msc2762.timeline:<roomId>
|
|
org.matrix.msc2762.send.event:m.room.message#m.text
|
|
org.matrix.msc2762.receive.event:m.room.message#m.text
|
|
org.matrix.msc2762.receive.event:m.room.message#m.notice
|
|
org.matrix.msc2762.receive.event:m.room.message#m.image
|
|
org.matrix.msc2762.receive.event:m.room.redaction
|
|
org.matrix.msc2762.receive.state_event:m.room.member
|
|
```
|
|
|
|
Anything else is silently dropped by the host. The capability set is
|
|
identical to the Telegram widget's M13 expansion — the host driver
|
|
already supports `m.image` + `m.room.redaction`.
|
|
|
|
## Local development
|
|
|
|
```bash
|
|
cd apps/widget-whatsapp && npm install
|
|
cd /home/ubuntu/projects/vojo/cinny && cat > config.local.json <<'JSON'
|
|
{
|
|
"bots": [
|
|
{ "id": "whatsapp", "experience": { "type": "matrix-widget", "url": "http://localhost:8083/" } }
|
|
]
|
|
}
|
|
JSON
|
|
```
|
|
|
|
Run both servers:
|
|
|
|
```bash
|
|
# terminal 1 — widget on :8083 with HMR
|
|
cd apps/widget-whatsapp && npm run dev
|
|
|
|
# terminal 2 — host SPA on :8080
|
|
cd /home/ubuntu/projects/vojo/cinny && npm start
|
|
```
|
|
|
|
Open `http://localhost:8080/bots/whatsapp`. The host's URL validator
|
|
accepts `http://localhost:*` only in dev builds.
|
|
|
|
## Build
|
|
|
|
```bash
|
|
npm run build
|
|
```
|
|
|
|
Outputs to `apps/widget-whatsapp/dist/`. Deploy by rsyncing `dist/*` into
|
|
`~/vojo/widgets/whatsapp/` on the production host. The VSCode task
|
|
`Deploy widgets` already includes the third subshell — running it from
|
|
the host root pushes all three widgets in sequence.
|
|
|
|
## Capacitor (Android)
|
|
|
|
`capacitor.config.ts` already allows `widgets.vojo.chat` for the existing
|
|
TG / Discord widgets — no extra entry needed for WhatsApp.
|
|
|
|
## Hosting (server-side)
|
|
|
|
Same Caddy `widgets.vojo.chat` block as the other widgets — add a third
|
|
`handle_path /whatsapp/* { … }` block alongside `/telegram/*` and
|
|
`/discord/*`. Then `mkdir -p ~/vojo/widgets/whatsapp` on the server, run
|
|
the deploy task, and verify with
|
|
`curl -I https://widgets.vojo.chat/whatsapp/index.html`.
|
|
|
|
## Source-of-truth pointers
|
|
|
|
- mautrix-whatsapp connector: <https://github.com/mautrix/whatsapp/blob/main/pkg/connector/login.go>
|
|
- mautrix-whatsapp connector (post-login session events):
|
|
<https://github.com/mautrix/whatsapp/blob/main/pkg/connector/handlewhatsapp.go>
|
|
- whatsmeow QR format: <https://github.com/tulir/whatsmeow/blob/main/pair.go> (`makeQRData`)
|
|
- whatsmeow pairing-code: <https://github.com/tulir/whatsmeow/blob/main/pair-code.go> (`PairPhone`)
|
|
- bridgev2 commands layer (shared with mautrix-telegram):
|
|
<https://github.com/mautrix/go/blob/main/bridgev2/commands/login.go>
|
|
|
|
The dialect file `src/bridge-protocol/dialects/bridgev2_v0264.ts` has
|
|
inline upstream pointers per regex; when the bridge image is upgraded,
|
|
spot-check those pointers and either confirm the wording is still valid
|
|
or drop a sibling dialect file with new regexes.
|