@f2a/openclaw-f2a 0.3.3 → 0.3.4
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/F2AComponentRegistry.d.ts +195 -0
- package/dist/F2AComponentRegistry.d.ts.map +1 -0
- package/dist/F2AComponentRegistry.js +385 -0
- package/dist/F2AComponentRegistry.js.map +1 -0
- package/dist/F2ACore.d.ts +227 -0
- package/dist/F2ACore.d.ts.map +1 -0
- package/dist/F2ACore.js +648 -0
- package/dist/F2ACore.js.map +1 -0
- package/dist/F2AMessageRouter.d.ts +108 -0
- package/dist/F2AMessageRouter.d.ts.map +1 -0
- package/dist/F2AMessageRouter.js +157 -0
- package/dist/F2AMessageRouter.js.map +1 -0
- package/dist/F2AToolRegistry.d.ts +45 -0
- package/dist/F2AToolRegistry.d.ts.map +1 -0
- package/dist/F2AToolRegistry.js +79 -0
- package/dist/F2AToolRegistry.js.map +1 -0
- package/dist/F2AWebhookManager.d.ts +79 -0
- package/dist/F2AWebhookManager.d.ts.map +1 -0
- package/dist/F2AWebhookManager.js +241 -0
- package/dist/F2AWebhookManager.js.map +1 -0
- package/dist/agent-manager.js +6 -6
- package/dist/agent-manager.js.map +1 -1
- package/dist/announcement-queue.d.ts +1 -8
- package/dist/announcement-queue.d.ts.map +1 -1
- package/dist/announcement-queue.js +19 -19
- package/dist/announcement-queue.js.map +1 -1
- package/dist/claim-handlers.d.ts +13 -4
- package/dist/claim-handlers.d.ts.map +1 -1
- package/dist/claim-handlers.js +42 -13
- package/dist/claim-handlers.js.map +1 -1
- package/dist/connector-helpers.d.ts +143 -0
- package/dist/connector-helpers.d.ts.map +1 -0
- package/dist/connector-helpers.js +398 -0
- package/dist/connector-helpers.js.map +1 -0
- package/dist/connector.d.ts +87 -265
- package/dist/connector.d.ts.map +1 -1
- package/dist/connector.js +334 -2037
- package/dist/connector.js.map +1 -1
- package/dist/contact-manager.d.ts +1 -1
- package/dist/contact-manager.d.ts.map +1 -1
- package/dist/contact-manager.js +12 -5
- package/dist/contact-manager.js.map +1 -1
- package/dist/contact-tool-handlers.d.ts +72 -0
- package/dist/contact-tool-handlers.d.ts.map +1 -0
- package/dist/contact-tool-handlers.js +413 -0
- package/dist/contact-tool-handlers.js.map +1 -0
- package/dist/f2a-client.d.ts +168 -0
- package/dist/f2a-client.d.ts.map +1 -0
- package/dist/f2a-client.js +425 -0
- package/dist/f2a-client.js.map +1 -0
- package/dist/handshake-protocol.d.ts +3 -2
- package/dist/handshake-protocol.d.ts.map +1 -1
- package/dist/handshake-protocol.js +15 -6
- package/dist/handshake-protocol.js.map +1 -1
- package/dist/index.d.ts +12 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -45
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +31 -9
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +268 -12
- package/dist/logger.js.map +1 -1
- package/dist/network-client.d.ts +1 -8
- package/dist/network-client.d.ts.map +1 -1
- package/dist/network-client.js.map +1 -1
- package/dist/node-manager.d.ts +8 -8
- package/dist/node-manager.d.ts.map +1 -1
- package/dist/node-manager.js +100 -36
- package/dist/node-manager.js.map +1 -1
- package/dist/plugin.d.ts +2 -2
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +43 -23
- package/dist/plugin.js.map +1 -1
- package/dist/task-guard.d.ts.map +1 -1
- package/dist/task-guard.js +44 -38
- package/dist/task-guard.js.map +1 -1
- package/dist/task-queue.d.ts +2 -8
- package/dist/task-queue.d.ts.map +1 -1
- package/dist/task-queue.js +144 -119
- package/dist/task-queue.js.map +1 -1
- package/dist/tool-handlers.d.ts +15 -3
- package/dist/tool-handlers.d.ts.map +1 -1
- package/dist/tool-handlers.js +85 -54
- package/dist/tool-handlers.js.map +1 -1
- package/dist/tools/contact-tools.d.ts +18 -0
- package/dist/tools/contact-tools.d.ts.map +1 -0
- package/dist/tools/contact-tools.js +176 -0
- package/dist/tools/contact-tools.js.map +1 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +15 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/network-tools.d.ts +17 -0
- package/dist/tools/network-tools.d.ts.map +1 -0
- package/dist/tools/network-tools.js +106 -0
- package/dist/tools/network-tools.js.map +1 -0
- package/dist/tools/task-tools.d.ts +25 -0
- package/dist/tools/task-tools.d.ts.map +1 -0
- package/dist/tools/task-tools.js +275 -0
- package/dist/tools/task-tools.js.map +1 -0
- package/dist/types.d.ts +376 -12
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/webhook-handlers.d.ts +50 -0
- package/dist/webhook-handlers.d.ts.map +1 -0
- package/dist/webhook-handlers.js +183 -0
- package/dist/webhook-handlers.js.map +1 -0
- package/dist/webhook-pusher.d.ts +1 -8
- package/dist/webhook-pusher.d.ts.map +1 -1
- package/dist/webhook-pusher.js.map +1 -1
- package/dist/webhook-server.d.ts +3 -8
- package/dist/webhook-server.d.ts.map +1 -1
- package/dist/webhook-server.js +21 -4
- package/dist/webhook-server.js.map +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +7 -4
- package/dist/reputation.d.ts +0 -156
- package/dist/reputation.d.ts.map +0 -1
- package/dist/reputation.js +0 -432
- package/dist/reputation.js.map +0 -1
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* F2A Connector 辅助函数
|
|
4
|
+
*
|
|
5
|
+
* 提供验证、错误处理、路径安全等工具函数。
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.PATH_TRAVERSAL_PATTERNS = exports.MESSAGE_HASH_TTL_MS = exports.MAX_MESSAGE_HASH_CACHE_SIZE = exports.MESSAGE_HASH_THRESHOLD = exports.PEER_ID_REGEX = exports.MAX_MESSAGE_LENGTH = void 0;
|
|
9
|
+
exports.isValidPeerId = isValidPeerId;
|
|
10
|
+
exports.isPathSafe = isPathSafe;
|
|
11
|
+
exports.extractErrorMessage = extractErrorMessage;
|
|
12
|
+
exports.readAgentNameFromIdentity = readAgentNameFromIdentity;
|
|
13
|
+
exports.mergeConfig = mergeConfig;
|
|
14
|
+
exports.generateToken = generateToken;
|
|
15
|
+
exports.checkF2AInstalled = checkF2AInstalled;
|
|
16
|
+
exports.formatBroadcastResults = formatBroadcastResults;
|
|
17
|
+
exports.resolveAgent = resolveAgent;
|
|
18
|
+
exports.computeMessageHash = computeMessageHash;
|
|
19
|
+
exports.isEchoMessageByMetadata = isEchoMessageByMetadata;
|
|
20
|
+
exports.isEchoMessageByContent = isEchoMessageByContent;
|
|
21
|
+
exports.cleanupMessageHashCache = cleanupMessageHashCache;
|
|
22
|
+
exports.isDuplicateMessage = isDuplicateMessage;
|
|
23
|
+
const fs_1 = require("fs");
|
|
24
|
+
const path_1 = require("path");
|
|
25
|
+
const crypto_1 = require("crypto");
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// 常量
|
|
28
|
+
// ============================================================================
|
|
29
|
+
/** 消息最大长度 */
|
|
30
|
+
exports.MAX_MESSAGE_LENGTH = 1024 * 1024;
|
|
31
|
+
/** libp2p Peer ID 正则 */
|
|
32
|
+
exports.PEER_ID_REGEX = /^12D3KooW[A-Za-z1-9]{44}$/;
|
|
33
|
+
/** P2-6: 消息哈希去重阈值,短消息不计算哈希(性能优化) */
|
|
34
|
+
exports.MESSAGE_HASH_THRESHOLD = 100;
|
|
35
|
+
/** P1-3: 消息去重缓存最大条目数 */
|
|
36
|
+
exports.MAX_MESSAGE_HASH_CACHE_SIZE = 10000;
|
|
37
|
+
/** P1-3: 消息去重缓存条目最大存活时间(毫秒) */
|
|
38
|
+
exports.MESSAGE_HASH_TTL_MS = 5 * 60 * 1000; // 5 分钟
|
|
39
|
+
/** 路径遍历模式 */
|
|
40
|
+
exports.PATH_TRAVERSAL_PATTERNS = [
|
|
41
|
+
'../',
|
|
42
|
+
'..\\',
|
|
43
|
+
'%2e%2e%2f',
|
|
44
|
+
'%2e%2e/',
|
|
45
|
+
'..%2f',
|
|
46
|
+
'%2e%2e%5c',
|
|
47
|
+
'%2e%2e\\',
|
|
48
|
+
'..%5c',
|
|
49
|
+
];
|
|
50
|
+
// ============================================================================
|
|
51
|
+
// 验证函数
|
|
52
|
+
// ============================================================================
|
|
53
|
+
/**
|
|
54
|
+
* 验证 Peer ID 格式
|
|
55
|
+
*
|
|
56
|
+
* Peer ID 格式:12D3KooW + 44 个 Base58 字符 = 52 字符
|
|
57
|
+
*/
|
|
58
|
+
function isValidPeerId(peerId) {
|
|
59
|
+
if (typeof peerId !== 'string' || peerId.length === 0) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return exports.PEER_ID_REGEX.test(peerId);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 检查路径是否安全
|
|
66
|
+
*
|
|
67
|
+
* P2-1 修复:实现 allowedRoot 验证逻辑
|
|
68
|
+
*
|
|
69
|
+
* 允许绝对路径,但拒绝包含路径遍历字符的路径。
|
|
70
|
+
* 如果提供了 allowedRoot,则路径必须在该根目录范围内。
|
|
71
|
+
*/
|
|
72
|
+
function isPathSafe(path, options) {
|
|
73
|
+
if (typeof path !== 'string' || path.length === 0) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
// 允许绝对路径(workspace 配置通常是绝对路径)
|
|
77
|
+
// 拒绝包含路径遍历字符
|
|
78
|
+
if (path.includes('..') || path.includes('\0')) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
// 拒绝以 ~ 开头的路径(用户目录展开)
|
|
82
|
+
if (path.startsWith('~')) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
// 检查 URL 编码的路径遍历模式
|
|
86
|
+
const lowerPath = path.toLowerCase();
|
|
87
|
+
for (const pattern of exports.PATH_TRAVERSAL_PATTERNS) {
|
|
88
|
+
if (lowerPath.includes(pattern.toLowerCase())) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// P1-3 修复:循环解码 URL 编码直到无变化,防止多层编码绕过
|
|
93
|
+
// 例如:'%252e%252e' -> '%2e%2e' -> '..'
|
|
94
|
+
let decodedPath = path;
|
|
95
|
+
let prevPath = '';
|
|
96
|
+
let maxIterations = 10; // 防止无限循环
|
|
97
|
+
let iterations = 0;
|
|
98
|
+
while (decodedPath !== prevPath && iterations < maxIterations) {
|
|
99
|
+
prevPath = decodedPath;
|
|
100
|
+
try {
|
|
101
|
+
decodedPath = decodeURIComponent(decodedPath);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// 解码失败可能是恶意构造,拒绝
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
iterations++;
|
|
108
|
+
// 每次解码后检查路径遍历
|
|
109
|
+
if (decodedPath.includes('..') || decodedPath.includes('\0')) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
// 每次解码后检查 URL 编码模式(防止编码绕过)
|
|
113
|
+
const lowerDecoded = decodedPath.toLowerCase();
|
|
114
|
+
for (const pattern of exports.PATH_TRAVERSAL_PATTERNS) {
|
|
115
|
+
if (lowerDecoded.includes(pattern.toLowerCase())) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// P2-1 修复:实现 allowedRoot 验证逻辑
|
|
121
|
+
if (options?.allowedRoot) {
|
|
122
|
+
// 规范化路径(解析为绝对路径)
|
|
123
|
+
const absolutePath = (0, path_1.resolve)(path);
|
|
124
|
+
const absoluteRoot = (0, path_1.resolve)(options.allowedRoot);
|
|
125
|
+
// 计算相对路径,检查是否在允许范围内
|
|
126
|
+
const relativePath = (0, path_1.relative)(absoluteRoot, absolutePath);
|
|
127
|
+
// P1-4 修复:检查 relativePath 是否是绝对路径(使用 isAbsolute())
|
|
128
|
+
// Windows 上跨盘符路径如 "D:\..." 会返回绝对路径而非 ".." 开头
|
|
129
|
+
// 例如:relative("C:\root", "D:\escape") => "D:\escape"(绝对路径)
|
|
130
|
+
if ((0, path_1.isAbsolute)(relativePath)) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
// 如果相对路径以 '..' 开头,说明不在允许范围内
|
|
134
|
+
if (relativePath.startsWith('..')) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
// 如果配置了检查符号链接,验证符号链接不指向外部
|
|
138
|
+
if (options.checkSymlinks) {
|
|
139
|
+
try {
|
|
140
|
+
// 获取真实路径(解析符号链接)
|
|
141
|
+
const realPath = (0, fs_1.realpathSync)(absolutePath);
|
|
142
|
+
const realRoot = (0, fs_1.realpathSync)(absoluteRoot);
|
|
143
|
+
const realRelative = (0, path_1.relative)(realRoot, realPath);
|
|
144
|
+
if (realRelative.startsWith('..') || realRelative.startsWith('/')) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// 文件不存在时无法验证符号链接,保持谨慎
|
|
150
|
+
// 如果文件不存在,路径仍然可能是安全的(用于创建新文件)
|
|
151
|
+
// 但我们仍然检查前面的遍历限制
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
// ============================================================================
|
|
158
|
+
// 错误处理
|
|
159
|
+
// ============================================================================
|
|
160
|
+
/**
|
|
161
|
+
* 提取错误消息
|
|
162
|
+
*/
|
|
163
|
+
function extractErrorMessage(error) {
|
|
164
|
+
if (error instanceof Error) {
|
|
165
|
+
return error.message;
|
|
166
|
+
}
|
|
167
|
+
if (typeof error === 'string') {
|
|
168
|
+
return error;
|
|
169
|
+
}
|
|
170
|
+
if (error && typeof error === 'object' && 'message' in error) {
|
|
171
|
+
return String(error.message);
|
|
172
|
+
}
|
|
173
|
+
return String(error);
|
|
174
|
+
}
|
|
175
|
+
// ============================================================================
|
|
176
|
+
// Agent 信息
|
|
177
|
+
// ============================================================================
|
|
178
|
+
/**
|
|
179
|
+
* 从 IDENTITY.md 读取 Agent 名称
|
|
180
|
+
*/
|
|
181
|
+
function readAgentNameFromIdentity(workspace) {
|
|
182
|
+
if (!workspace)
|
|
183
|
+
return null;
|
|
184
|
+
const identityPath = (0, path_1.join)(workspace, 'IDENTITY.md');
|
|
185
|
+
if (!(0, fs_1.existsSync)(identityPath))
|
|
186
|
+
return null;
|
|
187
|
+
try {
|
|
188
|
+
const content = (0, fs_1.readFileSync)(identityPath, 'utf-8');
|
|
189
|
+
// 尝试从 markdown 提取 name
|
|
190
|
+
// 格式: - **Name:** AgentName
|
|
191
|
+
const nameMatch = content.match(/-\s*\*?\*?Name:?\*?\*?\s*(.+)/i);
|
|
192
|
+
if (nameMatch) {
|
|
193
|
+
const name = nameMatch[1].trim();
|
|
194
|
+
// 清理 markdown 格式
|
|
195
|
+
return name.replace(/\*\*/g, '').trim();
|
|
196
|
+
}
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// ============================================================================
|
|
204
|
+
// 配置
|
|
205
|
+
// ============================================================================
|
|
206
|
+
/**
|
|
207
|
+
* 合并配置
|
|
208
|
+
*/
|
|
209
|
+
function mergeConfig(config) {
|
|
210
|
+
const api = config._api;
|
|
211
|
+
const workspace = api?.config?.agents?.defaults?.workspace;
|
|
212
|
+
return {
|
|
213
|
+
autoStart: config.autoStart ?? true,
|
|
214
|
+
webhookPort: config.webhookPort ?? 9002,
|
|
215
|
+
webhookToken: config.webhookToken,
|
|
216
|
+
agentName: config.agentName ?? 'OpenClaw Agent',
|
|
217
|
+
capabilities: config.capabilities ?? [],
|
|
218
|
+
f2aPath: config.f2aPath,
|
|
219
|
+
controlPort: config.controlPort,
|
|
220
|
+
controlToken: config.controlToken,
|
|
221
|
+
p2pPort: config.p2pPort,
|
|
222
|
+
enableMDNS: config.enableMDNS,
|
|
223
|
+
bootstrapPeers: config.bootstrapPeers,
|
|
224
|
+
dataDir: config.dataDir,
|
|
225
|
+
maxQueuedTasks: config.maxQueuedTasks ?? 100,
|
|
226
|
+
pollInterval: config.pollInterval,
|
|
227
|
+
webhookPush: config.webhookPush,
|
|
228
|
+
reputation: config.reputation,
|
|
229
|
+
security: config.security,
|
|
230
|
+
handshake: config.handshake,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* 生成随机 Token
|
|
235
|
+
*
|
|
236
|
+
* P1-1 修复:使用 crypto.randomBytes() 替代 Math.random()
|
|
237
|
+
* 确保生成加密安全的随机 Token
|
|
238
|
+
* P2-7 优化:改用 hex 编码,简洁且无需替换逻辑
|
|
239
|
+
*/
|
|
240
|
+
function generateToken() {
|
|
241
|
+
const bytes = (0, crypto_1.randomBytes)(16); // 16 bytes = 32 hex chars
|
|
242
|
+
return bytes.toString('hex'); // 直接使用 hex 编码,无需手动替换
|
|
243
|
+
}
|
|
244
|
+
// ============================================================================
|
|
245
|
+
// Node 管理
|
|
246
|
+
// ============================================================================
|
|
247
|
+
/**
|
|
248
|
+
* 检查 F2A Node 是否已安装
|
|
249
|
+
*/
|
|
250
|
+
function checkF2AInstalled(nodePath) {
|
|
251
|
+
return (0, fs_1.existsSync)(nodePath);
|
|
252
|
+
}
|
|
253
|
+
// ============================================================================
|
|
254
|
+
// 结果格式化
|
|
255
|
+
// ============================================================================
|
|
256
|
+
/**
|
|
257
|
+
* 格式化广播结果
|
|
258
|
+
*/
|
|
259
|
+
function formatBroadcastResults(results) {
|
|
260
|
+
const successful = results.filter(r => r.success);
|
|
261
|
+
const failed = results.filter(r => !r.success);
|
|
262
|
+
let output = '';
|
|
263
|
+
if (successful.length > 0) {
|
|
264
|
+
output += `✅ 成功: ${successful.length} 个\n`;
|
|
265
|
+
for (const r of successful) {
|
|
266
|
+
output += ` ${r.name || r.peerId.slice(0, 20)}...\n`;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (failed.length > 0) {
|
|
270
|
+
output += `\n❌ 失败: ${failed.length} 个\n`;
|
|
271
|
+
for (const r of failed) {
|
|
272
|
+
output += ` ${r.name || r.peerId.slice(0, 20)}...\n`;
|
|
273
|
+
output += ` 错误: ${r.error || '未知错误'}\n`;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return output;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* 解析 Agent 引用
|
|
280
|
+
*
|
|
281
|
+
* 支持:
|
|
282
|
+
* - Peer ID(完整或前缀)
|
|
283
|
+
* - Agent 名称(精确或模糊匹配)
|
|
284
|
+
* - #索引格式(如 #1, #2)
|
|
285
|
+
*/
|
|
286
|
+
async function resolveAgent(agentRef, discoverAgents) {
|
|
287
|
+
const result = await discoverAgents();
|
|
288
|
+
if (!result?.success)
|
|
289
|
+
return null;
|
|
290
|
+
const agents = result.data || [];
|
|
291
|
+
// #索引格式
|
|
292
|
+
if (agentRef.startsWith('#')) {
|
|
293
|
+
const index = parseInt(agentRef.slice(1)) - 1;
|
|
294
|
+
return agents[index] || null;
|
|
295
|
+
}
|
|
296
|
+
// 精确匹配
|
|
297
|
+
const exact = agents.find((a) => a.peerId === agentRef ||
|
|
298
|
+
a.displayName === agentRef);
|
|
299
|
+
if (exact)
|
|
300
|
+
return exact;
|
|
301
|
+
// 模糊匹配
|
|
302
|
+
const fuzzy = agents.find((a) => a.peerId.startsWith(agentRef) ||
|
|
303
|
+
(a.displayName?.toLowerCase().includes(agentRef.toLowerCase()) ?? false));
|
|
304
|
+
return fuzzy || null;
|
|
305
|
+
}
|
|
306
|
+
// ============================================================================
|
|
307
|
+
// 消息处理辅助函数
|
|
308
|
+
// ============================================================================
|
|
309
|
+
/**
|
|
310
|
+
* P1-3: 计算消息内容哈希
|
|
311
|
+
* P2-2 修复:使用 crypto.createHash('sha256') 替代简单哈希
|
|
312
|
+
* 用于基于内容的去重
|
|
313
|
+
*
|
|
314
|
+
* @param from - 消息发送者 Peer ID
|
|
315
|
+
* @param content - 消息内容
|
|
316
|
+
* @returns SHA256 哈希字符串(前 32 字符作为标识)
|
|
317
|
+
*/
|
|
318
|
+
function computeMessageHash(from, content) {
|
|
319
|
+
const data = `${from}:${content}`;
|
|
320
|
+
// 使用 SHA256 算法生成安全的哈希值
|
|
321
|
+
const hash = (0, crypto_1.createHash)('sha256').update(data).digest('hex');
|
|
322
|
+
// 返回前 32 字符作为标识(足够用于去重)
|
|
323
|
+
return `msg-${hash.slice(0, 32)}-${data.length}`;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* P1-2, P1-5: 检测消息 metadata 中的回声标记
|
|
327
|
+
*
|
|
328
|
+
* 检查 metadata 中的特定标记,判断是否为应该跳过的回声消息。
|
|
329
|
+
* 这是 isEchoMessage 检测的第一层。
|
|
330
|
+
*
|
|
331
|
+
* @param metadata - 消息的 metadata 字段
|
|
332
|
+
* @returns 是否检测到回声标记
|
|
333
|
+
*/
|
|
334
|
+
function isEchoMessageByMetadata(metadata) {
|
|
335
|
+
if (!metadata)
|
|
336
|
+
return false;
|
|
337
|
+
// 检查是否是我们自己发出的回复标记
|
|
338
|
+
if (metadata.type === 'reply' && metadata.replyTo) {
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
// 检查显式的跳过标记
|
|
342
|
+
if (metadata._f2a_skip_echo === true || metadata['x-openclaw-skip'] === true) {
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* P1-2: 检测消息内容中的回声标记
|
|
349
|
+
*
|
|
350
|
+
* 检查消息内容中的特殊标记,判断是否为应该跳过的回声消息。
|
|
351
|
+
* 这是 isEchoMessage 检测的第二层。
|
|
352
|
+
*
|
|
353
|
+
* @param content - 消息内容
|
|
354
|
+
* @returns 是否检测到回声标记
|
|
355
|
+
*/
|
|
356
|
+
function isEchoMessageByContent(content) {
|
|
357
|
+
if (!content)
|
|
358
|
+
return false;
|
|
359
|
+
// 使用特殊的标记格式 [[F2A:REPLY:...]]
|
|
360
|
+
if (content.includes('[[F2A:REPLY:') || content.includes('[[reply_to_current]]')) {
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
// 检查是否以 NO_REPLY 标记开头(更严格)
|
|
364
|
+
if (content.startsWith('NO_REPLY:') || content.startsWith('[NO_REPLY]')) {
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* P1-3: 清理过期的消息哈希缓存
|
|
371
|
+
*
|
|
372
|
+
* @param cache - 消息哈希缓存 Map
|
|
373
|
+
* @param now - 当前时间戳
|
|
374
|
+
* @param ttl - 缓存条目存活时间(毫秒)
|
|
375
|
+
*/
|
|
376
|
+
function cleanupMessageHashCache(cache, now, ttl = exports.MESSAGE_HASH_TTL_MS) {
|
|
377
|
+
for (const [hash, timestamp] of cache.entries()) {
|
|
378
|
+
if (now - timestamp > ttl) {
|
|
379
|
+
cache.delete(hash);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* P1-3: 检查消息哈希是否为重复消息
|
|
385
|
+
*
|
|
386
|
+
* @param cache - 消息哈希缓存 Map
|
|
387
|
+
* @param messageHash - 消息哈希值
|
|
388
|
+
* @param now - 当前时间戳
|
|
389
|
+
* @param ttl - 缓存条目存活时间(毫秒)
|
|
390
|
+
* @returns 是否为重复消息(在 TTL 内已处理过)
|
|
391
|
+
*/
|
|
392
|
+
function isDuplicateMessage(cache, messageHash, now, ttl = exports.MESSAGE_HASH_TTL_MS) {
|
|
393
|
+
if (!cache.has(messageHash))
|
|
394
|
+
return false;
|
|
395
|
+
const processedTime = cache.get(messageHash);
|
|
396
|
+
return now - processedTime < ttl;
|
|
397
|
+
}
|
|
398
|
+
//# sourceMappingURL=connector-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector-helpers.js","sourceRoot":"","sources":["../src/connector-helpers.ts"],"names":[],"mappings":"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"}
|