3.5 KiB
3.5 KiB
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(likeextensions/googlechat/src/runtime.ts). - Registers channel + HTTP handler.
- Stores
- 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_v1text 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.
- Token manager:
Webhook verification and decryption
URL verification
- Feishu sends a payload (plain or encrypted) where
type === "url_verification"and includeschallenge. - The handler responds
200with JSON:{"challenge":"<challenge>"}.
Decrypt algorithm
- If payload has
encrypt:- Compute AES key =
sha256(encryptKey)bytes (32 bytes). - Decode
encryptfrom base64. - IV = first 16 bytes; ciphertext = remaining bytes.
- Decrypt via
aes-256-cbcto UTF-8 JSON.
- Compute AES key =
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
encryptKeyis not configured, validateverificationTokenagainst payloadtoken(orheader.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
resolveMentionGatingWithBypasswithrequireMentionfrom 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.