@dsh-overdrive/gateway 0.1.4 → 0.1.5
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.
- package/dist/adapter.d.ts +7 -1
- package/dist/adapters/cli.d.ts +4 -1
- package/dist/adapters/cli.js +1 -1
- package/dist/adapters/cli.js.map +1 -1
- package/dist/adapters/dingtalk.d.ts +13 -5
- package/dist/adapters/dingtalk.js +27 -15
- package/dist/adapters/dingtalk.js.map +1 -1
- package/dist/adapters/discord.d.ts +4 -1
- package/dist/adapters/discord.js +4 -1
- package/dist/adapters/discord.js.map +1 -1
- package/dist/adapters/feishu.d.ts +4 -1
- package/dist/adapters/feishu.js +9 -3
- package/dist/adapters/feishu.js.map +1 -1
- package/dist/adapters/slack.d.ts +4 -1
- package/dist/adapters/slack.js +8 -3
- package/dist/adapters/slack.js.map +1 -1
- package/dist/adapters/telegram.d.ts +4 -1
- package/dist/adapters/telegram.js +5 -1
- package/dist/adapters/telegram.js.map +1 -1
- package/dist/adapters/wecom.d.ts +4 -1
- package/dist/adapters/wecom.js +1 -1
- package/dist/adapters/wecom.js.map +1 -1
- package/dist/adapters/whatsapp.d.ts +4 -1
- package/dist/adapters/whatsapp.js +8 -2
- package/dist/adapters/whatsapp.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +13 -3
- package/dist/index.js.map +1 -1
- package/dist/session.d.ts +6 -2
- package/dist/session.js +8 -3
- package/dist/session.js.map +1 -1
- package/package.json +2 -2
- package/src/adapter.ts +8 -1
- package/src/adapters/cli.ts +3 -3
- package/src/adapters/dingtalk.ts +37 -17
- package/src/adapters/discord.ts +6 -3
- package/src/adapters/feishu.ts +16 -5
- package/src/adapters/slack.ts +14 -4
- package/src/adapters/telegram.ts +7 -3
- package/src/adapters/wecom.ts +3 -3
- package/src/adapters/whatsapp.ts +10 -4
- package/src/index.ts +15 -3
- package/src/session.ts +9 -3
- package/test/adapters.dingtalk.test.ts +11 -5
- package/test/multi.test.ts +29 -8
- package/test/session.test.ts +7 -2
- package/test/streaming.test.ts +162 -162
package/dist/index.js
CHANGED
|
@@ -108,7 +108,7 @@ async function handleCommand(adapter, client, command, sessionId, chatId, aggreg
|
|
|
108
108
|
}
|
|
109
109
|
/** 单个适配器的接线:白名单 → 命令面/upsert → sendMessage;按钮 → resolveApproval;事件流经轨迹聚合。 */
|
|
110
110
|
export async function wireAdapter(adapter, client, opts) {
|
|
111
|
-
const allow = new Allowlist(opts.allowlist);
|
|
111
|
+
const allow = new Allowlist(opts.allowlist, opts.allowAll);
|
|
112
112
|
const chatIds = new Map();
|
|
113
113
|
const aggregator = new TrajectoryAggregator();
|
|
114
114
|
const deltas = new DeltaTracker();
|
|
@@ -147,7 +147,7 @@ export async function wireAdapter(adapter, client, opts) {
|
|
|
147
147
|
await adapter.send(msg.chatId, { text: `❌ 出错了:${message}` }).catch(() => undefined);
|
|
148
148
|
}
|
|
149
149
|
});
|
|
150
|
-
adapter.onReply(async (buttonId) => {
|
|
150
|
+
adapter.onReply(async (buttonId, sender) => {
|
|
151
151
|
try {
|
|
152
152
|
const idx = buttonId.indexOf(':');
|
|
153
153
|
if (idx < 0)
|
|
@@ -155,6 +155,15 @@ export async function wireAdapter(adapter, client, opts) {
|
|
|
155
155
|
const action = buttonId.slice(0, idx);
|
|
156
156
|
const reqId = buttonId.slice(idx + 1);
|
|
157
157
|
if ((action === 'approve' || action === 'reject') && reqId) {
|
|
158
|
+
// 安全边界:审批按钮必须校验点击者(维护者评审指出:未授权用户可代授权)
|
|
159
|
+
const senderKey = buildSessionKey(adapter.id, { chatId: sender.chatId, userId: sender.userId });
|
|
160
|
+
if (!allow.allows(senderKey)) {
|
|
161
|
+
console.warn(`[gateway][${adapter.id}] 按钮点击者不在白名单,拒绝批准: ${senderKey}`);
|
|
162
|
+
if (sender.chatId) {
|
|
163
|
+
await adapter.send(sender.chatId, { text: '⛔ 你不在白名单里,不能批准该操作。' }).catch(() => undefined);
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
158
167
|
await client.resolveApproval(reqId, action);
|
|
159
168
|
}
|
|
160
169
|
}
|
|
@@ -192,6 +201,7 @@ async function main() {
|
|
|
192
201
|
const dshToken = process.env.DSH_TOKEN ?? 'dev-token';
|
|
193
202
|
const allowlist = (process.env.ALLOWLIST ?? '')
|
|
194
203
|
.split(',').map((s) => s.trim()).filter(Boolean);
|
|
204
|
+
const allowAll = process.env.ALLOW_ALL === '1';
|
|
195
205
|
const adapterIds = parseAdapterIds(process.env.GATEWAY_ADAPTERS ?? 'cli');
|
|
196
206
|
const env = adapterEnvFromProcess();
|
|
197
207
|
const asr = createTranscriber({
|
|
@@ -206,7 +216,7 @@ async function main() {
|
|
|
206
216
|
const adapters = adapterIds.map((id) => createAdapter(id, env));
|
|
207
217
|
for (const adapter of adapters) {
|
|
208
218
|
await adapter.connect();
|
|
209
|
-
await wireAdapter(adapter, client, { allowlist, asr });
|
|
219
|
+
await wireAdapter(adapter, client, { allowlist, allowAll, asr });
|
|
210
220
|
console.log(`[gateway] ${adapter.id} 适配器已就绪`);
|
|
211
221
|
}
|
|
212
222
|
const consolePort = Number(process.env.GATEWAY_CONSOLE_PORT ?? 3190);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/session.d.ts
CHANGED
|
@@ -2,9 +2,13 @@ export declare function buildSessionKey(adapterId: string, msg: {
|
|
|
2
2
|
chatId: string;
|
|
3
3
|
userId: string;
|
|
4
4
|
}): string;
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* 白名单:默认 fail-closed —— 只有显式配置了条目才放行;
|
|
7
|
+
* 开发环境可用 ALLOW_ALL=1 显式放行所有(比空列表隐式放行安全得多)。
|
|
8
|
+
*/
|
|
6
9
|
export declare class Allowlist {
|
|
7
10
|
private readonly entries;
|
|
8
|
-
|
|
11
|
+
private readonly allowAll;
|
|
12
|
+
constructor(entries: string[], allowAll?: boolean);
|
|
9
13
|
allows(key: string): boolean;
|
|
10
14
|
}
|
package/dist/session.js
CHANGED
|
@@ -2,14 +2,19 @@ import { sessionKey } from '@dsh-overdrive/sdk';
|
|
|
2
2
|
export function buildSessionKey(adapterId, msg) {
|
|
3
3
|
return sessionKey(adapterId, msg.chatId, msg.userId);
|
|
4
4
|
}
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* 白名单:默认 fail-closed —— 只有显式配置了条目才放行;
|
|
7
|
+
* 开发环境可用 ALLOW_ALL=1 显式放行所有(比空列表隐式放行安全得多)。
|
|
8
|
+
*/
|
|
6
9
|
export class Allowlist {
|
|
7
10
|
entries;
|
|
8
|
-
|
|
11
|
+
allowAll;
|
|
12
|
+
constructor(entries, allowAll = false) {
|
|
9
13
|
this.entries = entries;
|
|
14
|
+
this.allowAll = allowAll;
|
|
10
15
|
}
|
|
11
16
|
allows(key) {
|
|
12
|
-
return this.entries.length
|
|
17
|
+
return this.allowAll || (this.entries.length > 0 && this.entries.includes(key));
|
|
13
18
|
}
|
|
14
19
|
}
|
|
15
20
|
//# sourceMappingURL=session.js.map
|
package/dist/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,MAAM,UAAU,eAAe,CAC7B,SAAiB,EACjB,GAAuC;IAEvC,OAAO,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;AACvD,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,MAAM,UAAU,eAAe,CAC7B,SAAiB,EACjB,GAAuC;IAEvC,OAAO,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;AACvD,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,SAAS;IAED;IACA;IAFnB,YACmB,OAAiB,EACjB,WAAW,KAAK;QADhB,YAAO,GAAP,OAAO,CAAU;QACjB,aAAQ,GAAR,QAAQ,CAAQ;IAChC,CAAC;IAEJ,MAAM,CAAC,GAAW;QAChB,OAAO,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IAClF,CAAC;CACF"}
|
package/package.json
CHANGED
package/src/adapter.ts
CHANGED
|
@@ -12,6 +12,12 @@ export interface OutboundPayload {
|
|
|
12
12
|
buttons?: OutboundButton[];
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/** 按钮回执的点击者身份(用于白名单校验)。chatId 在个别平台回调中可能缺失,缺失时按未授权处理(fail-closed)。 */
|
|
16
|
+
export interface ReplySender {
|
|
17
|
+
chatId: string;
|
|
18
|
+
userId: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
15
21
|
/** 平台适配器契约:M2/M3 的 WhatsApp/Telegram/… 都实现它。 */
|
|
16
22
|
export interface Adapter {
|
|
17
23
|
readonly id: string;
|
|
@@ -22,5 +28,6 @@ export interface Adapter {
|
|
|
22
28
|
/** 可选:连接状态(供控制台)。 */
|
|
23
29
|
status?(): { connected: boolean };
|
|
24
30
|
onMessage(cb: (msg: NormalizedMessage) => void): void;
|
|
25
|
-
|
|
31
|
+
/** 按钮点击回执:buttonId + 点击者身份。身份缺失即传空字符串,由上层按未授权处理。 */
|
|
32
|
+
onReply(cb: (buttonId: string, sender: ReplySender) => void): void;
|
|
26
33
|
}
|
package/src/adapters/cli.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { Adapter, NormalizedMessage, OutboundPayload } from '../adapter.js'
|
|
|
5
5
|
export class CliAdapter implements Adapter {
|
|
6
6
|
readonly id = 'cli';
|
|
7
7
|
private messageCb?: (msg: NormalizedMessage) => void;
|
|
8
|
-
private replyCb?: (buttonId: string) => void;
|
|
8
|
+
private replyCb?: (buttonId: string, sender: { chatId: string; userId: string }) => void;
|
|
9
9
|
private rl?: ReturnType<typeof createInterface>;
|
|
10
10
|
|
|
11
11
|
async connect(): Promise<void> {
|
|
@@ -15,7 +15,7 @@ export class CliAdapter implements Adapter {
|
|
|
15
15
|
if (!trimmed) return;
|
|
16
16
|
const btn = trimmed.match(/^\/btn\s+(\S+)$/i);
|
|
17
17
|
if (btn) {
|
|
18
|
-
this.replyCb?.(btn[1]);
|
|
18
|
+
this.replyCb?.(btn[1], { chatId: 'cli', userId: 'local' });
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
this.messageCb?.({ chatId: 'cli', userId: 'local', text: trimmed });
|
|
@@ -31,7 +31,7 @@ export class CliAdapter implements Adapter {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
onMessage(cb: (msg: NormalizedMessage) => void): void { this.messageCb = cb; }
|
|
34
|
-
onReply(cb: (buttonId: string) => void): void { this.replyCb = cb; }
|
|
34
|
+
onReply(cb: (buttonId: string, sender: { chatId: string; userId: string }) => void): void { this.replyCb = cb; }
|
|
35
35
|
/** CLI 是本地进程内适配器:恒为已连接。 */
|
|
36
36
|
status(): { connected: boolean } { return { connected: true }; }
|
|
37
37
|
}
|
package/src/adapters/dingtalk.ts
CHANGED
|
@@ -70,31 +70,46 @@ export function buildActionCard(text: string, buttons: OutboundButton[]): {
|
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
export interface CardCallbackResult {
|
|
74
|
+
buttonId: string;
|
|
75
|
+
chatId?: string;
|
|
76
|
+
userId?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
73
79
|
/**
|
|
74
|
-
* 钉钉卡片回调载荷 →
|
|
75
|
-
* Stream 模式下回调 JSON 的字段名(cardCallbackData / params / cardActionData
|
|
76
|
-
*
|
|
80
|
+
* 钉钉卡片回调载荷 → { buttonId, chatId?, userId? }。
|
|
81
|
+
* Stream 模式下回调 JSON 的字段名(cardCallbackData / params / cardActionData,以及会话/用户字段)
|
|
82
|
+
* 在不同卡片版本有差异,这里做多路径深度兜底解析;真机验证后可按实际字段收敛。找不到返回 null。
|
|
77
83
|
*/
|
|
78
|
-
export function parseCardCallback(raw: unknown):
|
|
79
|
-
|
|
80
|
-
|
|
84
|
+
export function parseCardCallback(raw: unknown): CardCallbackResult | null {
|
|
85
|
+
let buttonId: string | null = null;
|
|
86
|
+
let chatId: string | undefined;
|
|
87
|
+
let userId: string | undefined;
|
|
88
|
+
|
|
89
|
+
const visit = (obj: unknown, depth: number): void => {
|
|
90
|
+
if (depth > 5 || !obj || typeof obj !== 'object') return;
|
|
81
91
|
for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {
|
|
82
|
-
if (typeof value === 'string' && (key === 'cardCallbackData' || key === 'params' || key === 'cardActionData')) {
|
|
92
|
+
if (!buttonId && typeof value === 'string' && (key === 'cardCallbackData' || key === 'params' || key === 'cardActionData')) {
|
|
83
93
|
try {
|
|
84
94
|
const parsed = JSON.parse(value) as { action?: string; reqId?: string };
|
|
85
95
|
if ((parsed.action === 'approve' || parsed.action === 'reject') && typeof parsed.reqId === 'string' && parsed.reqId) {
|
|
86
|
-
|
|
96
|
+
buttonId = `${parsed.action}:${parsed.reqId}`;
|
|
87
97
|
}
|
|
88
98
|
} catch {
|
|
89
99
|
/* 该字段不是 JSON 载荷,继续往下找 */
|
|
90
100
|
}
|
|
91
101
|
}
|
|
92
|
-
|
|
93
|
-
|
|
102
|
+
if (!chatId && typeof value === 'string' && (key === 'conversationId' || key === 'conversation_id') && value) {
|
|
103
|
+
chatId = value;
|
|
104
|
+
}
|
|
105
|
+
if (!userId && typeof value === 'string' && (key === 'senderStaffId' || key === 'senderId' || key === 'userid' || key === 'userId') && value) {
|
|
106
|
+
userId = value;
|
|
107
|
+
}
|
|
108
|
+
if (typeof value === 'object') visit(value, depth + 1);
|
|
94
109
|
}
|
|
95
|
-
return null;
|
|
96
110
|
};
|
|
97
|
-
|
|
111
|
+
visit(raw, 0);
|
|
112
|
+
return buttonId ? { buttonId, chatId, userId } : null;
|
|
98
113
|
}
|
|
99
114
|
|
|
100
115
|
// ── 适配器 ────────────────────────────────────────────────────
|
|
@@ -109,7 +124,7 @@ export class DingTalkAdapter implements Adapter {
|
|
|
109
124
|
private client?: DWClient;
|
|
110
125
|
private connected = false;
|
|
111
126
|
private messageCb?: (msg: NormalizedMessage) => void;
|
|
112
|
-
private replyCb?: (buttonId: string) => void;
|
|
127
|
+
private replyCb?: (buttonId: string, sender: { chatId: string; userId: string }) => void;
|
|
113
128
|
private readonly pendingButtons = new PendingButtons();
|
|
114
129
|
/** conversationId → 最近的 sessionWebhook(回复通道,过期由钉钉侧管理) */
|
|
115
130
|
private readonly webhooks = new Map<string, string>();
|
|
@@ -131,7 +146,7 @@ export class DingTalkAdapter implements Adapter {
|
|
|
131
146
|
this.webhooks.set(parsed.chatId, parsed.sessionWebhook);
|
|
132
147
|
const button = this.pendingButtons.match(parsed.chatId, parsed.text);
|
|
133
148
|
if (button) {
|
|
134
|
-
this.replyCb?.(button.id);
|
|
149
|
+
this.replyCb?.(button.id, { chatId: parsed.chatId, userId: parsed.userId });
|
|
135
150
|
return;
|
|
136
151
|
}
|
|
137
152
|
this.messageCb?.({ chatId: parsed.chatId, userId: parsed.userId, text: parsed.text });
|
|
@@ -144,8 +159,13 @@ export class DingTalkAdapter implements Adapter {
|
|
|
144
159
|
} catch {
|
|
145
160
|
return;
|
|
146
161
|
}
|
|
147
|
-
const
|
|
148
|
-
if (
|
|
162
|
+
const result = parseCardCallback(data);
|
|
163
|
+
if (result) {
|
|
164
|
+
this.replyCb?.(result.buttonId, {
|
|
165
|
+
chatId: result.chatId ?? result.userId ?? '',
|
|
166
|
+
userId: result.userId ?? '',
|
|
167
|
+
});
|
|
168
|
+
}
|
|
149
169
|
});
|
|
150
170
|
await client.connect();
|
|
151
171
|
this.connected = true;
|
|
@@ -181,6 +201,6 @@ export class DingTalkAdapter implements Adapter {
|
|
|
181
201
|
}
|
|
182
202
|
|
|
183
203
|
onMessage(cb: (msg: NormalizedMessage) => void): void { this.messageCb = cb; }
|
|
184
|
-
onReply(cb: (buttonId: string) => void): void { this.replyCb = cb; }
|
|
204
|
+
onReply(cb: (buttonId: string, sender: { chatId: string; userId: string }) => void): void { this.replyCb = cb; }
|
|
185
205
|
status(): { connected: boolean } { return { connected: this.connected }; }
|
|
186
206
|
}
|
package/src/adapters/discord.ts
CHANGED
|
@@ -64,7 +64,7 @@ export class DiscordAdapter implements Adapter {
|
|
|
64
64
|
private readonly client: Client;
|
|
65
65
|
private connected = false;
|
|
66
66
|
private messageCb?: (msg: NormalizedMessage) => void;
|
|
67
|
-
private replyCb?: (buttonId: string) => void;
|
|
67
|
+
private replyCb?: (buttonId: string, sender: { chatId: string; userId: string }) => void;
|
|
68
68
|
|
|
69
69
|
constructor(opts: DiscordAdapterOptions) {
|
|
70
70
|
this.client = new Client({
|
|
@@ -89,7 +89,10 @@ export class DiscordAdapter implements Adapter {
|
|
|
89
89
|
if (!interaction.isButton()) return;
|
|
90
90
|
const button = interaction as ButtonInteraction;
|
|
91
91
|
await button.deferUpdate().catch(() => undefined);
|
|
92
|
-
this.replyCb?.(button.customId
|
|
92
|
+
this.replyCb?.(button.customId, {
|
|
93
|
+
chatId: button.channelId,
|
|
94
|
+
userId: button.user.id,
|
|
95
|
+
});
|
|
93
96
|
});
|
|
94
97
|
}
|
|
95
98
|
|
|
@@ -112,6 +115,6 @@ export class DiscordAdapter implements Adapter {
|
|
|
112
115
|
}
|
|
113
116
|
|
|
114
117
|
onMessage(cb: (msg: NormalizedMessage) => void): void { this.messageCb = cb; }
|
|
115
|
-
onReply(cb: (buttonId: string) => void): void { this.replyCb = cb; }
|
|
118
|
+
onReply(cb: (buttonId: string, sender: { chatId: string; userId: string }) => void): void { this.replyCb = cb; }
|
|
116
119
|
status(): { connected: boolean } { return { connected: this.connected }; }
|
|
117
120
|
}
|
package/src/adapters/feishu.ts
CHANGED
|
@@ -96,7 +96,7 @@ export class FeishuAdapter implements Adapter {
|
|
|
96
96
|
private ws?: InstanceType<typeof WSClient>;
|
|
97
97
|
private connected = false;
|
|
98
98
|
private messageCb?: (msg: NormalizedMessage) => void;
|
|
99
|
-
private replyCb?: (buttonId: string) => void;
|
|
99
|
+
private replyCb?: (buttonId: string, sender: { chatId: string; userId: string }) => void;
|
|
100
100
|
private readonly pendingButtons = new PendingButtons();
|
|
101
101
|
/** chatId → 最近一条入站消息的 message_id(send 优先 reply,缺失则 create 兜底) */
|
|
102
102
|
private readonly lastMessageIds = new Map<string, string>();
|
|
@@ -117,15 +117,26 @@ export class FeishuAdapter implements Adapter {
|
|
|
117
117
|
const chatId = normalized.chatId;
|
|
118
118
|
const button = this.pendingButtons.match(chatId, normalized.text);
|
|
119
119
|
if (button) {
|
|
120
|
-
this.replyCb?.(button.id);
|
|
120
|
+
this.replyCb?.(button.id, { chatId, userId: normalized.userId });
|
|
121
121
|
return;
|
|
122
122
|
}
|
|
123
123
|
this.messageCb?.(normalized);
|
|
124
124
|
},
|
|
125
125
|
// 原生交互卡片按钮回调 → 审批应答(Roadmap v0.2)
|
|
126
|
-
|
|
126
|
+
// 载荷字段(operator.open_id / context.open_chat_id)取自官方卡片回调事件;
|
|
127
|
+
// 个别版本字段名可能不同 —— 拿不到身份时上层按未授权处理(fail-closed),编号回复兜底不受影响。
|
|
128
|
+
'card.action.trigger': async (data: {
|
|
129
|
+
action?: { value?: unknown };
|
|
130
|
+
operator?: { open_id?: string };
|
|
131
|
+
context?: { open_chat_id?: string };
|
|
132
|
+
}) => {
|
|
127
133
|
const buttonId = cardActionToButtonId(data?.action?.value);
|
|
128
|
-
if (buttonId)
|
|
134
|
+
if (buttonId) {
|
|
135
|
+
this.replyCb?.(buttonId, {
|
|
136
|
+
chatId: data?.context?.open_chat_id ?? '',
|
|
137
|
+
userId: data?.operator?.open_id ?? '',
|
|
138
|
+
});
|
|
139
|
+
}
|
|
129
140
|
},
|
|
130
141
|
});
|
|
131
142
|
this.ws = new WSClient({
|
|
@@ -175,6 +186,6 @@ export class FeishuAdapter implements Adapter {
|
|
|
175
186
|
}
|
|
176
187
|
|
|
177
188
|
onMessage(cb: (msg: NormalizedMessage) => void): void { this.messageCb = cb; }
|
|
178
|
-
onReply(cb: (buttonId: string) => void): void { this.replyCb = cb; }
|
|
189
|
+
onReply(cb: (buttonId: string, sender: { chatId: string; userId: string }) => void): void { this.replyCb = cb; }
|
|
179
190
|
status(): { connected: boolean } { return { connected: this.connected }; }
|
|
180
191
|
}
|
package/src/adapters/slack.ts
CHANGED
|
@@ -69,7 +69,7 @@ export class SlackAdapter implements Adapter {
|
|
|
69
69
|
private readonly app: InstanceType<typeof App>;
|
|
70
70
|
private connected = false;
|
|
71
71
|
private messageCb?: (msg: NormalizedMessage) => void;
|
|
72
|
-
private replyCb?: (buttonId: string) => void;
|
|
72
|
+
private replyCb?: (buttonId: string, sender: { chatId: string; userId: string }) => void;
|
|
73
73
|
|
|
74
74
|
constructor(opts: SlackAdapterOptions) {
|
|
75
75
|
this.app = new App({ token: opts.botToken, appToken: opts.appToken, socketMode: true });
|
|
@@ -82,8 +82,18 @@ export class SlackAdapter implements Adapter {
|
|
|
82
82
|
});
|
|
83
83
|
this.app.action(/^approve:|^reject:/, async ({ ack, body, respond }) => {
|
|
84
84
|
await ack();
|
|
85
|
-
const
|
|
86
|
-
|
|
85
|
+
const b = body as {
|
|
86
|
+
actions?: Array<{ value?: string }>;
|
|
87
|
+
user?: { id?: string };
|
|
88
|
+
channel?: { id?: string };
|
|
89
|
+
};
|
|
90
|
+
const action = b.actions?.[0];
|
|
91
|
+
if (action?.value) {
|
|
92
|
+
this.replyCb?.(action.value, {
|
|
93
|
+
chatId: b.channel?.id ?? '',
|
|
94
|
+
userId: b.user?.id ?? '',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
87
97
|
await respond({ text: '处理中…', replace_original: false }).catch(() => undefined);
|
|
88
98
|
});
|
|
89
99
|
await this.app.start(0); // Socket Mode 不需要端口;start(0) 仅建立连接
|
|
@@ -100,6 +110,6 @@ export class SlackAdapter implements Adapter {
|
|
|
100
110
|
}
|
|
101
111
|
|
|
102
112
|
onMessage(cb: (msg: NormalizedMessage) => void): void { this.messageCb = cb; }
|
|
103
|
-
onReply(cb: (buttonId: string) => void): void { this.replyCb = cb; }
|
|
113
|
+
onReply(cb: (buttonId: string, sender: { chatId: string; userId: string }) => void): void { this.replyCb = cb; }
|
|
104
114
|
status(): { connected: boolean } { return { connected: this.connected }; }
|
|
105
115
|
}
|
package/src/adapters/telegram.ts
CHANGED
|
@@ -69,7 +69,7 @@ export class TelegramAdapter implements Adapter {
|
|
|
69
69
|
private readonly token: string;
|
|
70
70
|
private connected = false;
|
|
71
71
|
private messageCb?: (msg: NormalizedMessage) => void;
|
|
72
|
-
private replyCb?: (buttonId: string) => void;
|
|
72
|
+
private replyCb?: (buttonId: string, sender: { chatId: string; userId: string }) => void;
|
|
73
73
|
|
|
74
74
|
constructor(opts: TelegramAdapterOptions) {
|
|
75
75
|
this.token = opts.token;
|
|
@@ -86,7 +86,11 @@ export class TelegramAdapter implements Adapter {
|
|
|
86
86
|
this.bot.on('callback_query:data', async (ctx) => {
|
|
87
87
|
const data = ctx.callbackQuery.data;
|
|
88
88
|
await ctx.answerCallbackQuery().catch(() => undefined);
|
|
89
|
-
|
|
89
|
+
const chat = ctx.callbackQuery.message?.chat as { id?: number | string } | undefined;
|
|
90
|
+
this.replyCb?.(data, {
|
|
91
|
+
chatId: String(chat?.id ?? ''),
|
|
92
|
+
userId: String(ctx.callbackQuery.from.id),
|
|
93
|
+
});
|
|
90
94
|
});
|
|
91
95
|
this.bot.catch((err) => console.error('[telegram]', err));
|
|
92
96
|
void this.bot.start(); // 长轮询(自托管无需 webhook)
|
|
@@ -124,6 +128,6 @@ export class TelegramAdapter implements Adapter {
|
|
|
124
128
|
}
|
|
125
129
|
|
|
126
130
|
onMessage(cb: (msg: NormalizedMessage) => void): void { this.messageCb = cb; }
|
|
127
|
-
onReply(cb: (buttonId: string) => void): void { this.replyCb = cb; }
|
|
131
|
+
onReply(cb: (buttonId: string, sender: { chatId: string; userId: string }) => void): void { this.replyCb = cb; }
|
|
128
132
|
status(): { connected: boolean } { return { connected: this.connected }; }
|
|
129
133
|
}
|
package/src/adapters/wecom.ts
CHANGED
|
@@ -98,7 +98,7 @@ export class WeComAdapter implements Adapter {
|
|
|
98
98
|
private server?: ReturnType<typeof createServer>;
|
|
99
99
|
private connected = false;
|
|
100
100
|
private messageCb?: (msg: NormalizedMessage) => void;
|
|
101
|
-
private replyCb?: (buttonId: string) => void;
|
|
101
|
+
private replyCb?: (buttonId: string, sender: { chatId: string; userId: string }) => void;
|
|
102
102
|
private readonly pendingButtons = new PendingButtons();
|
|
103
103
|
/** access_token 缓存:企业微信 token 有效期 7200s,且有获取频率限制,必须复用。 */
|
|
104
104
|
private tokenCache?: { token: string; expiresAt: number };
|
|
@@ -143,7 +143,7 @@ export class WeComAdapter implements Adapter {
|
|
|
143
143
|
if (!normalized) return;
|
|
144
144
|
const button = this.pendingButtons.match(normalized.chatId, normalized.text);
|
|
145
145
|
if (button) {
|
|
146
|
-
this.replyCb?.(button.id);
|
|
146
|
+
this.replyCb?.(button.id, { chatId: normalized.chatId, userId: normalized.userId });
|
|
147
147
|
return;
|
|
148
148
|
}
|
|
149
149
|
this.messageCb?.(normalized);
|
|
@@ -178,7 +178,7 @@ export class WeComAdapter implements Adapter {
|
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
onMessage(cb: (msg: NormalizedMessage) => void): void { this.messageCb = cb; }
|
|
181
|
-
onReply(cb: (buttonId: string) => void): void { this.replyCb = cb; }
|
|
181
|
+
onReply(cb: (buttonId: string, sender: { chatId: string; userId: string }) => void): void { this.replyCb = cb; }
|
|
182
182
|
status(): { connected: boolean } { return { connected: this.connected }; }
|
|
183
183
|
}
|
|
184
184
|
|
package/src/adapters/whatsapp.ts
CHANGED
|
@@ -129,7 +129,7 @@ export class WhatsAppAdapter implements Adapter {
|
|
|
129
129
|
private sock?: WASocket;
|
|
130
130
|
private connected = false;
|
|
131
131
|
private messageCb?: (msg: NormalizedMessage) => void;
|
|
132
|
-
private replyCb?: (buttonId: string) => void;
|
|
132
|
+
private replyCb?: (buttonId: string, sender: { chatId: string; userId: string }) => void;
|
|
133
133
|
/** chatId → 当前 pending 按钮(编号回复 → 按钮 id,带 TTL 防过期误吞) */
|
|
134
134
|
private readonly pendingButtons = new PendingButtons();
|
|
135
135
|
|
|
@@ -175,7 +175,10 @@ export class WhatsAppAdapter implements Adapter {
|
|
|
175
175
|
if (buttonId) {
|
|
176
176
|
const chatId = waRaw.key?.remoteJid;
|
|
177
177
|
if (chatId) this.pendingButtons.consume(chatId);
|
|
178
|
-
this.replyCb?.(buttonId
|
|
178
|
+
this.replyCb?.(buttonId, {
|
|
179
|
+
chatId: chatId ?? '',
|
|
180
|
+
userId: waRaw.key?.participant ?? chatId ?? '',
|
|
181
|
+
});
|
|
179
182
|
continue;
|
|
180
183
|
}
|
|
181
184
|
const normalized = normalizeWhatsAppMessage(waRaw);
|
|
@@ -183,7 +186,10 @@ export class WhatsAppAdapter implements Adapter {
|
|
|
183
186
|
// 编号回复兜底:若该 chat 有 pending 按钮且消息是数字(TTL 内),转成按钮点击
|
|
184
187
|
const button = this.pendingButtons.match(normalized.msg.chatId, normalized.msg.text);
|
|
185
188
|
if (button) {
|
|
186
|
-
this.replyCb?.(button.id
|
|
189
|
+
this.replyCb?.(button.id, {
|
|
190
|
+
chatId: normalized.msg.chatId,
|
|
191
|
+
userId: normalized.msg.userId,
|
|
192
|
+
});
|
|
187
193
|
continue;
|
|
188
194
|
}
|
|
189
195
|
this.messageCb?.(normalized.msg);
|
|
@@ -223,6 +229,6 @@ export class WhatsAppAdapter implements Adapter {
|
|
|
223
229
|
}
|
|
224
230
|
|
|
225
231
|
onMessage(cb: (msg: NormalizedMessage) => void): void { this.messageCb = cb; }
|
|
226
|
-
onReply(cb: (buttonId: string) => void): void { this.replyCb = cb; }
|
|
232
|
+
onReply(cb: (buttonId: string, sender: { chatId: string; userId: string }) => void): void { this.replyCb = cb; }
|
|
227
233
|
status(): { connected: boolean } { return { connected: this.connected }; }
|
|
228
234
|
}
|
package/src/index.ts
CHANGED
|
@@ -65,6 +65,8 @@ export function planOutbound(ev: ServerEvent): { payload: OutboundPayload } | nu
|
|
|
65
65
|
|
|
66
66
|
export interface WireOptions {
|
|
67
67
|
allowlist: string[];
|
|
68
|
+
/** 开发逃生口:ALLOW_ALL=1 跳过白名单(生产勿开)。 */
|
|
69
|
+
allowAll?: boolean;
|
|
68
70
|
/** ASR 转写器;配置了 API key 时启用,语音消息转成文本再发给 agent。 */
|
|
69
71
|
asr?: AsrTranscriber;
|
|
70
72
|
}
|
|
@@ -131,7 +133,7 @@ export async function wireAdapter(
|
|
|
131
133
|
client: GatewayClient,
|
|
132
134
|
opts: WireOptions,
|
|
133
135
|
): Promise<void> {
|
|
134
|
-
const allow = new Allowlist(opts.allowlist);
|
|
136
|
+
const allow = new Allowlist(opts.allowlist, opts.allowAll);
|
|
135
137
|
const chatIds = new Map<string, string>();
|
|
136
138
|
const aggregator = new TrajectoryAggregator();
|
|
137
139
|
const deltas = new DeltaTracker();
|
|
@@ -174,13 +176,22 @@ export async function wireAdapter(
|
|
|
174
176
|
}
|
|
175
177
|
});
|
|
176
178
|
|
|
177
|
-
adapter.onReply(async (buttonId) => {
|
|
179
|
+
adapter.onReply(async (buttonId, sender) => {
|
|
178
180
|
try {
|
|
179
181
|
const idx = buttonId.indexOf(':');
|
|
180
182
|
if (idx < 0) return;
|
|
181
183
|
const action = buttonId.slice(0, idx) as 'approve' | 'reject';
|
|
182
184
|
const reqId = buttonId.slice(idx + 1);
|
|
183
185
|
if ((action === 'approve' || action === 'reject') && reqId) {
|
|
186
|
+
// 安全边界:审批按钮必须校验点击者(维护者评审指出:未授权用户可代授权)
|
|
187
|
+
const senderKey = buildSessionKey(adapter.id, { chatId: sender.chatId, userId: sender.userId });
|
|
188
|
+
if (!allow.allows(senderKey)) {
|
|
189
|
+
console.warn(`[gateway][${adapter.id}] 按钮点击者不在白名单,拒绝批准: ${senderKey}`);
|
|
190
|
+
if (sender.chatId) {
|
|
191
|
+
await adapter.send(sender.chatId, { text: '⛔ 你不在白名单里,不能批准该操作。' }).catch(() => undefined);
|
|
192
|
+
}
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
184
195
|
await client.resolveApproval(reqId, action);
|
|
185
196
|
}
|
|
186
197
|
} catch (error) {
|
|
@@ -221,6 +232,7 @@ async function main(): Promise<void> {
|
|
|
221
232
|
const dshToken = process.env.DSH_TOKEN ?? 'dev-token';
|
|
222
233
|
const allowlist = (process.env.ALLOWLIST ?? '')
|
|
223
234
|
.split(',').map((s) => s.trim()).filter(Boolean);
|
|
235
|
+
const allowAll = process.env.ALLOW_ALL === '1';
|
|
224
236
|
const adapterIds = parseAdapterIds(process.env.GATEWAY_ADAPTERS ?? 'cli');
|
|
225
237
|
const env = adapterEnvFromProcess();
|
|
226
238
|
const asr = createTranscriber({
|
|
@@ -236,7 +248,7 @@ async function main(): Promise<void> {
|
|
|
236
248
|
const adapters: Adapter[] = adapterIds.map((id) => createAdapter(id, env));
|
|
237
249
|
for (const adapter of adapters) {
|
|
238
250
|
await adapter.connect();
|
|
239
|
-
await wireAdapter(adapter, client, { allowlist, asr });
|
|
251
|
+
await wireAdapter(adapter, client, { allowlist, allowAll, asr });
|
|
240
252
|
console.log(`[gateway] ${adapter.id} 适配器已就绪`);
|
|
241
253
|
}
|
|
242
254
|
|
package/src/session.ts
CHANGED
|
@@ -7,11 +7,17 @@ export function buildSessionKey(
|
|
|
7
7
|
return sessionKey(adapterId, msg.chatId, msg.userId);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* 白名单:默认 fail-closed —— 只有显式配置了条目才放行;
|
|
12
|
+
* 开发环境可用 ALLOW_ALL=1 显式放行所有(比空列表隐式放行安全得多)。
|
|
13
|
+
*/
|
|
11
14
|
export class Allowlist {
|
|
12
|
-
constructor(
|
|
15
|
+
constructor(
|
|
16
|
+
private readonly entries: string[],
|
|
17
|
+
private readonly allowAll = false,
|
|
18
|
+
) {}
|
|
13
19
|
|
|
14
20
|
allows(key: string): boolean {
|
|
15
|
-
return this.entries.length
|
|
21
|
+
return this.allowAll || (this.entries.length > 0 && this.entries.includes(key));
|
|
16
22
|
}
|
|
17
23
|
}
|
|
@@ -37,13 +37,19 @@ describe('buildActionCard(钉钉 actionCard)', () => {
|
|
|
37
37
|
});
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
describe('parseCardCallback(TOPIC_CARD 回调载荷 → 按钮 id
|
|
40
|
+
describe('parseCardCallback(TOPIC_CARD 回调载荷 → 按钮 id + 身份)', () => {
|
|
41
41
|
it('识别 cardCallbackData 字段', () => {
|
|
42
|
-
expect(parseCardCallback({ cardPrivateData: { cardCallbackData: '{"action":"approve","reqId":"r1"}' } })).
|
|
42
|
+
expect(parseCardCallback({ cardPrivateData: { cardCallbackData: '{"action":"approve","reqId":"r1"}' } })).toMatchObject({ buttonId: 'approve:r1' });
|
|
43
43
|
});
|
|
44
44
|
it('识别 params / cardActionData 字段与嵌套结构', () => {
|
|
45
|
-
expect(parseCardCallback({ cardPrivateData: { params: '{"action":"reject","reqId":"r9"}' } })).
|
|
46
|
-
expect(parseCardCallback({ a: { b: { cardActionData: '{"action":"approve","reqId":"x"}' } } })).
|
|
45
|
+
expect(parseCardCallback({ cardPrivateData: { params: '{"action":"reject","reqId":"r9"}' } })).toMatchObject({ buttonId: 'reject:r9' });
|
|
46
|
+
expect(parseCardCallback({ a: { b: { cardActionData: '{"action":"approve","reqId":"x"}' } } })).toMatchObject({ buttonId: 'approve:x' });
|
|
47
|
+
});
|
|
48
|
+
it('带回会话与用户身份(用于白名单校验)', () => {
|
|
49
|
+
expect(parseCardCallback({
|
|
50
|
+
cardPrivateData: { cardCallbackData: '{"action":"approve","reqId":"r1"}', userId: 'u1' },
|
|
51
|
+
conversationId: 'cid1',
|
|
52
|
+
})).toEqual({ buttonId: 'approve:r1', chatId: 'cid1', userId: 'u1' });
|
|
47
53
|
});
|
|
48
54
|
it('非法载荷返回 null', () => {
|
|
49
55
|
expect(parseCardCallback(null)).toBeNull();
|
|
@@ -53,6 +59,6 @@ describe('parseCardCallback(TOPIC_CARD 回调载荷 → 按钮 id)', () => {
|
|
|
53
59
|
});
|
|
54
60
|
it('buttonCallbackData 与 parseCardCallback 往返一致', () => {
|
|
55
61
|
const data = buttonCallbackData({ id: 'reject:r7', label: 'x' });
|
|
56
|
-
expect(parseCardCallback({ cardPrivateData: { cardCallbackData: data } })).
|
|
62
|
+
expect(parseCardCallback({ cardPrivateData: { cardCallbackData: data } })).toMatchObject({ buttonId: 'reject:r7' });
|
|
57
63
|
});
|
|
58
64
|
});
|