@yaoqi10012/wechat-kf 0.3.1

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.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/dist/accounts.d.ts +38 -0
  3. package/dist/accounts.js +247 -0
  4. package/dist/accounts.js.map +1 -0
  5. package/dist/api.d.ts +58 -0
  6. package/dist/api.js +200 -0
  7. package/dist/api.js.map +1 -0
  8. package/dist/bot.d.ts +37 -0
  9. package/dist/bot.js +672 -0
  10. package/dist/bot.js.map +1 -0
  11. package/dist/channel.d.ts +14 -0
  12. package/dist/channel.js +320 -0
  13. package/dist/channel.js.map +1 -0
  14. package/dist/config-schema.d.ts +56 -0
  15. package/dist/config-schema.js +39 -0
  16. package/dist/config-schema.js.map +1 -0
  17. package/dist/constants.d.ts +41 -0
  18. package/dist/constants.js +51 -0
  19. package/dist/constants.js.map +1 -0
  20. package/dist/crypto.d.ts +18 -0
  21. package/dist/crypto.js +81 -0
  22. package/dist/crypto.js.map +1 -0
  23. package/dist/fs-utils.d.ts +7 -0
  24. package/dist/fs-utils.js +13 -0
  25. package/dist/fs-utils.js.map +1 -0
  26. package/dist/monitor.d.ts +31 -0
  27. package/dist/monitor.js +80 -0
  28. package/dist/monitor.js.map +1 -0
  29. package/dist/outbound.d.ts +32 -0
  30. package/dist/outbound.js +411 -0
  31. package/dist/outbound.js.map +1 -0
  32. package/dist/reply-dispatcher.d.ts +36 -0
  33. package/dist/reply-dispatcher.js +216 -0
  34. package/dist/reply-dispatcher.js.map +1 -0
  35. package/dist/runtime.d.ts +12 -0
  36. package/dist/runtime.js +23 -0
  37. package/dist/runtime.js.map +1 -0
  38. package/dist/send-utils.d.ts +52 -0
  39. package/dist/send-utils.js +217 -0
  40. package/dist/send-utils.js.map +1 -0
  41. package/dist/token.d.ts +8 -0
  42. package/dist/token.js +61 -0
  43. package/dist/token.js.map +1 -0
  44. package/dist/types.d.ts +236 -0
  45. package/dist/types.js +3 -0
  46. package/dist/types.js.map +1 -0
  47. package/dist/unicode-format.d.ts +26 -0
  48. package/dist/unicode-format.js +157 -0
  49. package/dist/unicode-format.js.map +1 -0
  50. package/dist/webhook.d.ts +22 -0
  51. package/dist/webhook.js +148 -0
  52. package/dist/webhook.js.map +1 -0
  53. package/dist/wechat-kf-directives.d.ts +157 -0
  54. package/dist/wechat-kf-directives.js +576 -0
  55. package/dist/wechat-kf-directives.js.map +1 -0
  56. package/openclaw.plugin.json +31 -0
  57. package/package.json +92 -0
@@ -0,0 +1,236 @@
1
+ export type WechatKfConfig = {
2
+ enabled?: boolean;
3
+ corpId?: string;
4
+ appSecret?: string;
5
+ token?: string;
6
+ encodingAESKey?: string;
7
+ webhookPath?: string;
8
+ dmPolicy?: "open" | "pairing" | "allowlist" | "disabled";
9
+ allowFrom?: string[];
10
+ debounceMs?: number;
11
+ };
12
+ export type ResolvedWechatKfAccount = {
13
+ accountId: string;
14
+ enabled: boolean;
15
+ configured: boolean;
16
+ corpId?: string;
17
+ appSecret?: string;
18
+ token?: string;
19
+ encodingAESKey?: string;
20
+ openKfId?: string;
21
+ webhookPath: string;
22
+ config: WechatKfConfig;
23
+ };
24
+ export type WechatAccessTokenResponse = {
25
+ errcode: number;
26
+ errmsg: string;
27
+ access_token: string;
28
+ expires_in: number;
29
+ };
30
+ export type WechatKfSyncMsgRequest = {
31
+ cursor?: string;
32
+ token?: string;
33
+ limit?: number;
34
+ voice_format?: number;
35
+ open_kfid?: string;
36
+ };
37
+ export type WechatKfMergedMsgItem = {
38
+ sender_name?: string;
39
+ msg_content?: string;
40
+ send_time?: number;
41
+ msgtype?: string;
42
+ };
43
+ export type WechatKfMessage = {
44
+ msgid: string;
45
+ open_kfid: string;
46
+ external_userid: string;
47
+ send_time: number;
48
+ origin: number;
49
+ servicer_userid?: string;
50
+ msgtype: string;
51
+ text?: {
52
+ content: string;
53
+ menu_id?: string;
54
+ };
55
+ image?: {
56
+ media_id: string;
57
+ };
58
+ voice?: {
59
+ media_id: string;
60
+ };
61
+ video?: {
62
+ media_id: string;
63
+ };
64
+ file?: {
65
+ media_id: string;
66
+ };
67
+ location?: {
68
+ latitude: number;
69
+ longitude: number;
70
+ name: string;
71
+ address: string;
72
+ };
73
+ link?: {
74
+ title: string;
75
+ desc: string;
76
+ url: string;
77
+ pic_url: string;
78
+ };
79
+ event?: {
80
+ event_type: string;
81
+ open_kfid?: string;
82
+ external_userid?: string;
83
+ scene?: string;
84
+ scene_param?: string;
85
+ welcome_code?: string;
86
+ fail_msgid?: string;
87
+ fail_type?: number;
88
+ servicer_userid?: string;
89
+ status?: number;
90
+ };
91
+ merged_msg?: {
92
+ title?: string;
93
+ item?: WechatKfMergedMsgItem[];
94
+ };
95
+ channels?: {
96
+ nickname?: string;
97
+ title?: string;
98
+ sub_type?: number;
99
+ };
100
+ miniprogram?: {
101
+ title?: string;
102
+ appid?: string;
103
+ pagepath?: string;
104
+ thumb_media_id?: string;
105
+ };
106
+ business_card?: {
107
+ userid?: string;
108
+ };
109
+ msgmenu?: {
110
+ head_content?: string;
111
+ list?: {
112
+ id: string;
113
+ content?: string;
114
+ }[];
115
+ tail_content?: string;
116
+ };
117
+ channels_shop_product?: {
118
+ product_id?: string;
119
+ head_image?: string;
120
+ title?: string;
121
+ sales_price?: string;
122
+ shop_nickname?: string;
123
+ shop_head_image?: string;
124
+ };
125
+ channels_shop_order?: {
126
+ order_id?: string;
127
+ product_titles?: string;
128
+ price_wording?: string;
129
+ state?: string;
130
+ image_url?: string;
131
+ shop_nickname?: string;
132
+ };
133
+ };
134
+ export type WechatKfSyncMsgResponse = {
135
+ errcode: number;
136
+ errmsg: string;
137
+ next_cursor: string;
138
+ has_more: number;
139
+ msg_list: WechatKfMessage[];
140
+ };
141
+ export type WechatKfSendMsgRequest = {
142
+ touser: string;
143
+ open_kfid: string;
144
+ msgid?: string;
145
+ msgtype: string;
146
+ text?: {
147
+ content: string;
148
+ };
149
+ image?: {
150
+ media_id: string;
151
+ };
152
+ file?: {
153
+ media_id: string;
154
+ };
155
+ voice?: {
156
+ media_id: string;
157
+ };
158
+ video?: {
159
+ media_id: string;
160
+ };
161
+ link?: {
162
+ title: string;
163
+ desc?: string;
164
+ url: string;
165
+ thumb_media_id: string;
166
+ };
167
+ miniprogram?: {
168
+ appid: string;
169
+ title?: string;
170
+ thumb_media_id: string;
171
+ pagepath: string;
172
+ };
173
+ msgmenu?: {
174
+ head_content?: string;
175
+ list?: Array<{
176
+ type: "click";
177
+ click: {
178
+ id?: string;
179
+ content: string;
180
+ };
181
+ } | {
182
+ type: "view";
183
+ view: {
184
+ url: string;
185
+ content: string;
186
+ };
187
+ } | {
188
+ type: "miniprogram";
189
+ miniprogram: {
190
+ appid: string;
191
+ pagepath: string;
192
+ content: string;
193
+ };
194
+ } | {
195
+ type: "text";
196
+ text: {
197
+ content: string;
198
+ no_newline?: number;
199
+ };
200
+ }>;
201
+ tail_content?: string;
202
+ };
203
+ location?: {
204
+ name?: string;
205
+ address?: string;
206
+ latitude: number;
207
+ longitude: number;
208
+ };
209
+ business_card?: {
210
+ userid: string;
211
+ };
212
+ ca_link?: {
213
+ link_url: string;
214
+ };
215
+ };
216
+ export type WechatKfSendMsgResponse = {
217
+ errcode: number;
218
+ errmsg: string;
219
+ msgid: string;
220
+ };
221
+ export type WechatMediaUploadResponse = {
222
+ errcode: number;
223
+ errmsg: string;
224
+ type: string;
225
+ media_id: string;
226
+ created_at: number;
227
+ };
228
+ export type WechatCallbackXml = {
229
+ ToUserName: string;
230
+ CreateTime: string;
231
+ MsgType: string;
232
+ Event?: string;
233
+ Token?: string;
234
+ OpenKfId?: string;
235
+ Encrypt?: string;
236
+ };
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ // ── WeChat KF Plugin Types ──
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,+BAA+B"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Markdown → Unicode text formatting
3
+ *
4
+ * Converts markdown bold/italic/bold-italic to Unicode Mathematical
5
+ * Alphanumeric Symbols. Only converts ASCII letters (a-z, A-Z) and
6
+ * digits (0-9) — other characters pass through unchanged.
7
+ *
8
+ * This is meant for plain-text surfaces like WeChat KF where
9
+ * rich text / HTML isn't supported.
10
+ */
11
+ /**
12
+ * Convert markdown formatting to Unicode styled text.
13
+ *
14
+ * Handles:
15
+ * - `***text***` or `___text___` → bold italic
16
+ * - `**text**` or `__text__` → bold
17
+ * - `*text*` or `_text_` → italic
18
+ * - `` `code` `` → left as-is (backtick preserved)
19
+ * - ``` code blocks ``` → left as-is
20
+ * - `# headings` → 𝗛𝗲𝗮𝗱𝗶𝗻𝗴 (bold, # stripped)
21
+ * - `- list items` / `* list items` → • item
22
+ * - `1. numbered` → 1. (kept)
23
+ * - `[text](url)` → text (url)
24
+ * - `~~strikethrough~~` → stripped markers (no unicode strikethrough that's reliable)
25
+ */
26
+ export declare function markdownToUnicode(text: string): string;
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Markdown → Unicode text formatting
3
+ *
4
+ * Converts markdown bold/italic/bold-italic to Unicode Mathematical
5
+ * Alphanumeric Symbols. Only converts ASCII letters (a-z, A-Z) and
6
+ * digits (0-9) — other characters pass through unchanged.
7
+ *
8
+ * This is meant for plain-text surfaces like WeChat KF where
9
+ * rich text / HTML isn't supported.
10
+ */
11
+ // Unicode Mathematical Alphanumeric offsets for A-Z, a-z
12
+ // Bold: U+1D400 (A) / U+1D41A (a)
13
+ // Italic: U+1D434 (A) / U+1D44E (a)
14
+ // Bold Italic: U+1D468 (A) / U+1D482 (a)
15
+ // Bold digits: U+1D7CE (0)
16
+ const BOLD_UPPER_START = 0x1d400;
17
+ const BOLD_LOWER_START = 0x1d41a;
18
+ const BOLD_DIGIT_START = 0x1d7ce;
19
+ const ITALIC_UPPER_START = 0x1d434;
20
+ const ITALIC_LOWER_START = 0x1d44e;
21
+ // Italic has no digit variant — use normal digits
22
+ const BOLD_ITALIC_UPPER_START = 0x1d468;
23
+ const BOLD_ITALIC_LOWER_START = 0x1d482;
24
+ function mapChar(ch, upperStart, lowerStart, digitStart) {
25
+ const code = ch.charCodeAt(0);
26
+ if (code >= 65 && code <= 90) {
27
+ // A-Z
28
+ return String.fromCodePoint(upperStart + (code - 65));
29
+ }
30
+ if (code >= 97 && code <= 122) {
31
+ // a-z
32
+ return String.fromCodePoint(lowerStart + (code - 97));
33
+ }
34
+ if (digitStart !== undefined && code >= 48 && code <= 57) {
35
+ // 0-9
36
+ return String.fromCodePoint(digitStart + (code - 48));
37
+ }
38
+ return ch;
39
+ }
40
+ function toBold(text) {
41
+ return [...text].map((ch) => mapChar(ch, BOLD_UPPER_START, BOLD_LOWER_START, BOLD_DIGIT_START)).join("");
42
+ }
43
+ function toItalic(text) {
44
+ return [...text]
45
+ .map((ch) => {
46
+ // Special case: italic lowercase 'h' is U+210E (ℎ) not in the block
47
+ if (ch === "h")
48
+ return "\u210E";
49
+ return mapChar(ch, ITALIC_UPPER_START, ITALIC_LOWER_START);
50
+ })
51
+ .join("");
52
+ }
53
+ function toBoldItalic(text) {
54
+ return [...text].map((ch) => mapChar(ch, BOLD_ITALIC_UPPER_START, BOLD_ITALIC_LOWER_START)).join("");
55
+ }
56
+ /** Regex matching any placeholder inserted by steps 1-4. */
57
+ const PLACEHOLDER_RE = /\x00(?:CB|IC|ES)\d+\x00/g;
58
+ /**
59
+ * Apply a Unicode transform while preserving placeholder sequences.
60
+ * Splits text on placeholder boundaries, transforms only non-placeholder
61
+ * segments, and reassembles.
62
+ */
63
+ function applyTransform(text, transform) {
64
+ let result = "";
65
+ let lastIndex = 0;
66
+ for (const match of text.matchAll(PLACEHOLDER_RE)) {
67
+ const idx = match.index;
68
+ if (idx > lastIndex) {
69
+ result += transform(text.slice(lastIndex, idx));
70
+ }
71
+ result += match[0];
72
+ lastIndex = idx + match[0].length;
73
+ }
74
+ if (lastIndex < text.length) {
75
+ result += transform(text.slice(lastIndex));
76
+ }
77
+ return result;
78
+ }
79
+ /**
80
+ * Convert markdown formatting to Unicode styled text.
81
+ *
82
+ * Handles:
83
+ * - `***text***` or `___text___` → bold italic
84
+ * - `**text**` or `__text__` → bold
85
+ * - `*text*` or `_text_` → italic
86
+ * - `` `code` `` → left as-is (backtick preserved)
87
+ * - ``` code blocks ``` → left as-is
88
+ * - `# headings` → 𝗛𝗲𝗮𝗱𝗶𝗻𝗴 (bold, # stripped)
89
+ * - `- list items` / `* list items` → • item
90
+ * - `1. numbered` → 1. (kept)
91
+ * - `[text](url)` → text (url)
92
+ * - `~~strikethrough~~` → stripped markers (no unicode strikethrough that's reliable)
93
+ */
94
+ export function markdownToUnicode(text) {
95
+ if (!text)
96
+ return text;
97
+ // 1. Preserve code blocks
98
+ const codeBlocks = [];
99
+ let result = text.replace(/```[\s\S]*?```/g, (match) => {
100
+ codeBlocks.push(match.replace(/^```\w*\n?/, "").replace(/\n?```$/, ""));
101
+ return `\x00CB${codeBlocks.length - 1}\x00`;
102
+ });
103
+ // 2. Preserve inline code
104
+ const inlineCodes = [];
105
+ result = result.replace(/`([^`\n]+)`/g, (_match, code) => {
106
+ inlineCodes.push(code);
107
+ return `\x00IC${inlineCodes.length - 1}\x00`;
108
+ });
109
+ // 3. Images: ![alt](url) → [alt](url) (must come before link handling)
110
+ result = result.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, "[$1]($2)");
111
+ // 4. Escape characters: protect \* \_ \~ \` \# \[ \] \( \) \\ \- \!
112
+ const escapes = [];
113
+ result = result.replace(/\\([*_~`#[\]()\\!-])/g, (_m, ch) => {
114
+ escapes.push(ch);
115
+ return `\x00ES${escapes.length - 1}\x00`;
116
+ });
117
+ // 5. Links: [text](url) → text (url)
118
+ result = result.replace(/\[([^\]]*)\]\(([^)]+)\)/g, "$1 ($2)");
119
+ // 6. Headings: # text → bold text (before bold/italic so inner markers are also bolded)
120
+ result = result.replace(/^(#{1,6})\s+(.+)$/gm, (_m, _hashes, content) => {
121
+ // Strip any inline bold/italic markers before applying bold
122
+ const stripped = content.replace(/\*{1,3}([^*]+)\*{1,3}/g, "$1").replace(/_{1,3}([^_]+)_{1,3}/g, "$1");
123
+ return applyTransform(stripped, toBold);
124
+ });
125
+ // 7. Bold italic: ***text*** or ___text___ (multiline with [\s\S])
126
+ result = result.replace(/\*{3}([\s\S]+?)\*{3}/g, (_m, inner) => applyTransform(inner, toBoldItalic));
127
+ result = result.replace(/_{3}([\s\S]+?)_{3}/g, (_m, inner) => applyTransform(inner, toBoldItalic));
128
+ // 8. Bold: **text** or __text__ (multiline with [\s\S])
129
+ result = result.replace(/\*{2}([\s\S]+?)\*{2}/g, (_m, inner) => applyTransform(inner, toBold));
130
+ result = result.replace(/_{2}([\s\S]+?)_{2}/g, (_m, inner) => applyTransform(inner, toBold));
131
+ // 9. Italic: *text* or _text_ (but not inside words for _)
132
+ // Use [^*\n] to avoid matching list markers like "* item *"
133
+ result = result.replace(/(?<!\w)\*([^*\n]+?)\*(?!\w)/g, (_m, inner) => applyTransform(inner, toItalic));
134
+ result = result.replace(/(?<!\w)_([^_\n]+?)_(?!\w)/g, (_m, inner) => applyTransform(inner, toItalic));
135
+ // 10. Strikethrough: ~~text~~ → just remove markers
136
+ result = result.replace(/~~([\s\S]+?)~~/g, "$1");
137
+ // 11. Task lists (must come before unordered list handling)
138
+ result = result.replace(/^([ \t]*)-\s+\[x\]\s+/gm, "$1\u2611 ");
139
+ result = result.replace(/^([ \t]*)-\s+\[ \]\s+/gm, "$1\u2610 ");
140
+ // 12. Unordered list: - item or * item → • item
141
+ result = result.replace(/^[ \t]*[-*]\s+/gm, "• ");
142
+ // 13. Blockquotes: > text → ┃ text
143
+ result = result.replace(/^>\s?/gm, "┃ ");
144
+ // 14. Horizontal rules
145
+ result = result.replace(/^[-*_]{3,}$/gm, "─────────");
146
+ // 15. Restore code blocks with visual markers
147
+ result = result.replace(/\x00CB(\d+)\x00/g, (_m, idx) => {
148
+ const code = codeBlocks[Number(idx)] ?? "";
149
+ return `\n━━━ code ━━━\n${code}\n━━━━━━━━━━━━\n`;
150
+ });
151
+ // 16. Restore inline code with backtick markers
152
+ result = result.replace(/\x00IC(\d+)\x00/g, (_m, idx) => `\`${inlineCodes[Number(idx)] ?? ""}\``);
153
+ // 17. Restore escape characters
154
+ result = result.replace(/\x00ES(\d+)\x00/g, (_m, idx) => escapes[Number(idx)] ?? "");
155
+ return result;
156
+ }
157
+ //# sourceMappingURL=unicode-format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unicode-format.js","sourceRoot":"","sources":["../src/unicode-format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * HTTP webhook handler for WeChat KF callbacks
3
+ *
4
+ * Handles:
5
+ * - GET: URL verification (echostr decrypt)
6
+ * - POST: Event notification (decrypt XML → trigger sync_msg)
7
+ *
8
+ * Designed to be registered on the framework's shared gateway server
9
+ * via api.registerHttpRoute({ path, handler: handleWechatKfWebhook }).
10
+ */
11
+ import type { IncomingMessage, ServerResponse } from "node:http";
12
+ export declare function parseQuery(url: string): Record<string, string>;
13
+ export declare function readBody(req: IncomingMessage, maxSize?: number): Promise<string>;
14
+ /** Extract a tag value from XML string */
15
+ export declare function xmlTag(xml: string, tag: string): string | undefined;
16
+ /**
17
+ * Framework-compatible HTTP handler for WeChat KF webhooks.
18
+ *
19
+ * Returns `true` if the request was handled, `false` if the path doesn't
20
+ * match (so the framework can try other plugins).
21
+ */
22
+ export declare function handleWechatKfWebhook(req: IncomingMessage, res: ServerResponse): Promise<boolean>;
@@ -0,0 +1,148 @@
1
+ /**
2
+ * HTTP webhook handler for WeChat KF callbacks
3
+ *
4
+ * Handles:
5
+ * - GET: URL verification (echostr decrypt)
6
+ * - POST: Event notification (decrypt XML → trigger sync_msg)
7
+ *
8
+ * Designed to be registered on the framework's shared gateway server
9
+ * via api.registerHttpRoute({ path, handler: handleWechatKfWebhook }).
10
+ */
11
+ import { registerKfId } from "./accounts.js";
12
+ import { handleWebhookEvent } from "./bot.js";
13
+ import { formatError, logTag } from "./constants.js";
14
+ import { decrypt, verifySignature } from "./crypto.js";
15
+ import { getSharedContext } from "./monitor.js";
16
+ export function parseQuery(url) {
17
+ const idx = url.indexOf("?");
18
+ if (idx < 0)
19
+ return {};
20
+ const params = {};
21
+ for (const pair of url.slice(idx + 1).split("&")) {
22
+ const eqIdx = pair.indexOf("=");
23
+ if (eqIdx < 0)
24
+ continue;
25
+ const k = pair.slice(0, eqIdx);
26
+ const v = pair.slice(eqIdx + 1);
27
+ if (k)
28
+ params[decodeURIComponent(k)] = decodeURIComponent(v);
29
+ }
30
+ return params;
31
+ }
32
+ export function readBody(req, maxSize = 64 * 1024) {
33
+ return new Promise((resolve, reject) => {
34
+ const chunks = [];
35
+ let size = 0;
36
+ let rejected = false;
37
+ req.on("data", (c) => {
38
+ if (rejected)
39
+ return;
40
+ size += c.length;
41
+ if (size > maxSize) {
42
+ rejected = true;
43
+ req.removeAllListeners("data");
44
+ req.resume();
45
+ reject(new Error(`${logTag()} request body too large`));
46
+ return;
47
+ }
48
+ chunks.push(c);
49
+ });
50
+ req.on("end", () => {
51
+ if (!rejected)
52
+ resolve(Buffer.concat(chunks).toString("utf8"));
53
+ });
54
+ req.on("error", (err) => {
55
+ if (!rejected)
56
+ reject(err);
57
+ });
58
+ });
59
+ }
60
+ /** Extract a tag value from XML string */
61
+ export function xmlTag(xml, tag) {
62
+ const re = new RegExp(`<${tag}><!\\[CDATA\\[(.+?)\\]\\]></${tag}>|<${tag}>(.+?)</${tag}>`);
63
+ const m = xml.match(re);
64
+ return m?.[1] ?? m?.[2];
65
+ }
66
+ /**
67
+ * Framework-compatible HTTP handler for WeChat KF webhooks.
68
+ *
69
+ * Returns `true` if the request was handled, `false` if the path doesn't
70
+ * match (so the framework can try other plugins).
71
+ */
72
+ export async function handleWechatKfWebhook(req, res) {
73
+ const ctx = getSharedContext();
74
+ if (!ctx)
75
+ return false;
76
+ const url = req.url ?? "/";
77
+ const pathname = url.split("?")[0];
78
+ if (pathname !== ctx.webhookPath)
79
+ return false;
80
+ const query = parseQuery(url);
81
+ try {
82
+ if (req.method === "GET") {
83
+ const { msg_signature, timestamp, nonce, echostr } = query;
84
+ if (!msg_signature || !timestamp || !nonce || !echostr) {
85
+ res.writeHead(400);
86
+ res.end("missing params");
87
+ return true;
88
+ }
89
+ if (!verifySignature(ctx.callbackToken, timestamp, nonce, echostr, msg_signature)) {
90
+ ctx.botCtx.log?.warn(`${logTag()} callback signature verification failed (GET)`);
91
+ res.writeHead(403);
92
+ res.end("signature mismatch");
93
+ return true;
94
+ }
95
+ const { message } = decrypt(ctx.encodingAESKey, echostr);
96
+ res.writeHead(200, { "Content-Type": "text/plain" });
97
+ res.end(message);
98
+ return true;
99
+ }
100
+ if (req.method === "POST") {
101
+ const { msg_signature, timestamp, nonce } = query;
102
+ const body = await readBody(req);
103
+ const encryptedMsg = xmlTag(body, "Encrypt");
104
+ if (!encryptedMsg || !msg_signature || !timestamp || !nonce) {
105
+ res.writeHead(400);
106
+ res.end("bad request");
107
+ return true;
108
+ }
109
+ if (!verifySignature(ctx.callbackToken, timestamp, nonce, encryptedMsg, msg_signature)) {
110
+ ctx.botCtx.log?.warn(`${logTag()} callback signature verification failed (POST)`);
111
+ res.writeHead(403);
112
+ res.end("signature mismatch");
113
+ return true;
114
+ }
115
+ const { message } = decrypt(ctx.encodingAESKey, encryptedMsg);
116
+ const eventToken = xmlTag(message, "Token") ?? "";
117
+ const openKfId = xmlTag(message, "OpenKfId") ?? "";
118
+ res.writeHead(200, { "Content-Type": "text/plain" });
119
+ res.end("success");
120
+ Promise.resolve((async () => {
121
+ if (openKfId) {
122
+ await registerKfId(openKfId);
123
+ }
124
+ await handleWebhookEvent(ctx.botCtx, openKfId, eventToken);
125
+ })()).catch((err) => {
126
+ ctx.botCtx.log?.error(`${logTag()} webhook event processing error: ${formatError(err)}`);
127
+ });
128
+ return true;
129
+ }
130
+ res.writeHead(405);
131
+ res.end("method not allowed");
132
+ return true;
133
+ }
134
+ catch (err) {
135
+ if (err instanceof Error && err.message.includes("body too large")) {
136
+ res.writeHead(413);
137
+ res.end("payload too large");
138
+ return true;
139
+ }
140
+ ctx.botCtx.log?.error(`${logTag()} webhook error: ${formatError(err)}`);
141
+ if (!res.headersSent) {
142
+ res.writeHead(500);
143
+ res.end("internal error");
144
+ }
145
+ return true;
146
+ }
147
+ }
148
+ //# sourceMappingURL=webhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook.js","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"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"}