83 lines
3.5 KiB
Markdown
83 lines
3.5 KiB
Markdown
# Tech design: Feishu (飞书) channel plugin
|
||
|
||
## Summary
|
||
|
||
Implement `@clawdbot/feishu` as a channel extension that:
|
||
|
||
- Registers a channel plugin (`api.registerChannel`) and an HTTP handler (`api.registerHttpHandler`).
|
||
- Starts a per-account “monitor” on gateway start (via `plugin.gateway.startAccount`) that runs until aborted and manages runtime status.
|
||
- Uses the existing Clawdbot reply pipeline (`runtime.channel.reply.dispatchReplyWithBufferedBlockDispatcher`) to route inbound messages to an agent and send outbound replies back to Feishu.
|
||
|
||
This follows the proven “webhook channel” structure in `extensions/googlechat`, with an additional long-connection transport option.
|
||
|
||
## Architecture
|
||
|
||
### Components
|
||
|
||
- **Feishu plugin entrypoint**: `extensions/feishu/index.ts`
|
||
- Stores `PluginRuntime` (like `extensions/googlechat/src/runtime.ts`).
|
||
- Registers channel + HTTP handler.
|
||
- **Channel plugin**: `extensions/feishu/src/channel.ts`
|
||
- Config adapter (accounts, enabled/configured, allowFrom formatting).
|
||
- Outbound adapter (sendText).
|
||
- Security adapter (DM policy warnings, group policy warnings).
|
||
- Status adapter (probe + runtime snapshot).
|
||
- Gateway adapter (startAccount → register webhook target).
|
||
- **Monitor / webhook handler**: `extensions/feishu/src/monitor.ts`
|
||
- Parses raw body, validates signature/token, decrypts if needed.
|
||
- Handles `url_verification`.
|
||
- Handles `im.message.receive_v1` text messages.
|
||
- **Long connection monitor**: `extensions/feishu/src/ws.ts`
|
||
- Fetches long-connection endpoint config from Feishu.
|
||
- Connects to Feishu’s event WebSocket and acknowledges events quickly.
|
||
- **Inbound processing + routing**: `extensions/feishu/src/inbound.ts`
|
||
- Applies DM + group policies and mention gating.
|
||
- Builds inbound context and calls reply dispatcher.
|
||
- Sends replies via Feishu REST API.
|
||
- **API client**: `extensions/feishu/src/api.ts`
|
||
- Token manager: `tenant_access_token/internal` (self-built apps).
|
||
- Send message / reply message endpoints.
|
||
- Bot info (`/open-apis/bot/v3/info`) to detect mentions.
|
||
|
||
## Webhook verification and decryption
|
||
|
||
### URL verification
|
||
|
||
- Feishu sends a payload (plain or encrypted) where `type === "url_verification"` and includes `challenge`.
|
||
- The handler responds `200` with JSON: `{"challenge":"<challenge>"}`.
|
||
|
||
### Decrypt algorithm
|
||
|
||
- If payload has `encrypt`:
|
||
- Compute AES key = `sha256(encryptKey)` bytes (32 bytes).
|
||
- Decode `encrypt` from base64.
|
||
- IV = first 16 bytes; ciphertext = remaining bytes.
|
||
- Decrypt via `aes-256-cbc` to UTF-8 JSON.
|
||
|
||
### Signature validation (encrypted mode)
|
||
|
||
- Headers: `x-lark-request-timestamp`, `x-lark-request-nonce`, `x-lark-signature`.
|
||
- Compute: `sha256(timestamp + nonce + encryptKey + rawBodyString)` (hex).
|
||
- Compare with `x-lark-signature`.
|
||
- Use the raw request body string exactly as received (do not re-stringify parsed JSON).
|
||
|
||
### Token validation (non-encrypted mode)
|
||
|
||
- When `encryptKey` is not configured, validate `verificationToken` against payload `token` (or `header.token`).
|
||
|
||
## Mention gating
|
||
|
||
- Fetch and cache bot identity via `GET /open-apis/bot/v3/info`.
|
||
- In group chats:
|
||
- `wasMentioned = mentions.some(m => m.id.open_id === botOpenId || m.id.user_id === botUserId)`
|
||
- Apply `resolveMentionGatingWithBypass` with `requireMention` from group config or channel default.
|
||
|
||
## Test strategy
|
||
|
||
Colocate tests in `extensions/feishu/src/` (Vitest).
|
||
|
||
- Signature verification (valid/invalid).
|
||
- Decrypt (known encryptKey + payload → expected JSON).
|
||
- Target normalization.
|
||
- URL verification and event parsing.
|