@searchfe/openclaw-baiduapp 0.1.8 → 0.1.9-beta.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.
- package/README.md +19 -30
- package/dist/index.js +405 -326
- package/dist/index.js.map +1 -1
- package/openclaw.plugin.json +1 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { spawnSync } from 'child_process';
|
|
2
|
+
import readline from 'readline';
|
|
1
3
|
import path2 from 'path';
|
|
2
4
|
import { fileURLToPath } from 'url';
|
|
3
|
-
import
|
|
5
|
+
import crypto2 from 'crypto';
|
|
4
6
|
import { createRequire } from 'module';
|
|
5
7
|
import { lookup } from 'dns/promises';
|
|
6
8
|
import fs2 from 'fs/promises';
|
|
@@ -9,11 +11,120 @@ import fs from 'fs';
|
|
|
9
11
|
import { tmpdir } from 'os';
|
|
10
12
|
|
|
11
13
|
var __defProp = Object.defineProperty;
|
|
14
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
15
|
+
var __esm = (fn, res) => function __init() {
|
|
16
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
17
|
+
};
|
|
12
18
|
var __export = (target, all) => {
|
|
13
19
|
for (var name in all)
|
|
14
20
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
21
|
};
|
|
16
22
|
|
|
23
|
+
// src/auth/login.ts
|
|
24
|
+
var login_exports = {};
|
|
25
|
+
__export(login_exports, {
|
|
26
|
+
loginBaiduApp: () => loginBaiduApp
|
|
27
|
+
});
|
|
28
|
+
function createTerminalPrompter() {
|
|
29
|
+
const rl = readline.createInterface({
|
|
30
|
+
input: process.stdin,
|
|
31
|
+
output: process.stdout
|
|
32
|
+
});
|
|
33
|
+
const question = (message) => new Promise((resolve) => {
|
|
34
|
+
rl.question(message, (answer) => resolve(answer));
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
select: async (message, choices) => {
|
|
38
|
+
while (true) {
|
|
39
|
+
process.stdout.write(`${message}
|
|
40
|
+
`);
|
|
41
|
+
for (const [index, choice] of choices.entries()) {
|
|
42
|
+
process.stdout.write(`${index + 1}. ${choice}
|
|
43
|
+
`);
|
|
44
|
+
}
|
|
45
|
+
const answer = (await question("\u8BF7\u9009\u62E9\u5E8F\u53F7: ")).trim();
|
|
46
|
+
const choiceIndex = Number(answer);
|
|
47
|
+
if (Number.isInteger(choiceIndex) && choiceIndex >= 1 && choiceIndex <= choices.length) {
|
|
48
|
+
return choices[choiceIndex - 1];
|
|
49
|
+
}
|
|
50
|
+
process.stdout.write(`\u8BF7\u8F93\u5165 1-${choices.length} \u4E4B\u95F4\u7684\u5E8F\u53F7\u3002
|
|
51
|
+
`);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
text: async (message, opts) => {
|
|
55
|
+
while (true) {
|
|
56
|
+
const answer = (await question(`${message}: `)).trim();
|
|
57
|
+
if (!opts?.required || answer) {
|
|
58
|
+
return answer;
|
|
59
|
+
}
|
|
60
|
+
process.stdout.write("\u8BE5\u9879\u4E3A\u5FC5\u586B\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165\u3002\n");
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
close: () => {
|
|
64
|
+
rl.close();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function redactValue(value, opts) {
|
|
69
|
+
if (!value) {
|
|
70
|
+
return "(empty)";
|
|
71
|
+
}
|
|
72
|
+
const keepStart = opts?.keepStart ?? 2;
|
|
73
|
+
const keepEnd = opts?.keepEnd ?? 2;
|
|
74
|
+
if (value.length <= keepStart + keepEnd) {
|
|
75
|
+
return "*".repeat(value.length);
|
|
76
|
+
}
|
|
77
|
+
return `${value.slice(0, keepStart)}***${value.slice(-keepEnd)}`;
|
|
78
|
+
}
|
|
79
|
+
function setConfigValue(key, value) {
|
|
80
|
+
const args = ["config", "set", key, String(value)];
|
|
81
|
+
const result = spawnSync("openclaw", args, {
|
|
82
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
83
|
+
encoding: "utf8",
|
|
84
|
+
timeout: 15e3
|
|
85
|
+
});
|
|
86
|
+
if (result.status !== 0) {
|
|
87
|
+
const stderr = (result.stderr ?? "").trim();
|
|
88
|
+
throw new Error(`openclaw config set failed: ${stderr || `exit code ${result.status}`}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function loginBaiduApp(params) {
|
|
92
|
+
void params.cfg;
|
|
93
|
+
void params.verbose;
|
|
94
|
+
const agentId = params.accountId?.trim() || "main";
|
|
95
|
+
const prompter = createTerminalPrompter();
|
|
96
|
+
try {
|
|
97
|
+
const mode = await prompter.select("\u8BF7\u9009\u62E9\u767E\u5EA6 App \u914D\u7F6E\u65B9\u5F0F", [
|
|
98
|
+
"\u624B\u52A8\u586B\u5199",
|
|
99
|
+
"\u626B\u7801\u914D\u7F6E\uFF08\u5373\u5C06\u652F\u6301\uFF09"
|
|
100
|
+
]);
|
|
101
|
+
if (mode === "\u626B\u7801\u914D\u7F6E\uFF08\u5373\u5C06\u652F\u6301\uFF09") {
|
|
102
|
+
params.runtime.log("\u23F3 \u626B\u7801\u914D\u7F6E\u529F\u80FD\u6B63\u5728\u5F00\u53D1\u4E2D\uFF0C\u656C\u8BF7\u671F\u5F85...");
|
|
103
|
+
params.runtime.log("\u8BF7\u5148\u4F7F\u7528\u624B\u52A8\u586B\u5199\u65B9\u5F0F\u5B8C\u6210\u914D\u7F6E\u3002");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const appKey = await prompter.text("App Key", { required: true });
|
|
107
|
+
const appSecret = await prompter.text("App Secret", { required: true });
|
|
108
|
+
const accountKeyPrefix = `channels.openclaw-baiduapp.accounts.${agentId}`;
|
|
109
|
+
setConfigValue(`${accountKeyPrefix}.appKey`, appKey);
|
|
110
|
+
setConfigValue(`${accountKeyPrefix}.appSecret`, appSecret);
|
|
111
|
+
setConfigValue(`${accountKeyPrefix}.enabled`, true);
|
|
112
|
+
params.runtime.log(`\u2705 openclaw-baiduapp \u5DF2\u5B8C\u6210\u914D\u7F6E\uFF08account: ${agentId}\uFF09`);
|
|
113
|
+
params.runtime.log(`- appKey: ${redactValue(appKey, { keepStart: 3, keepEnd: 3 })}`);
|
|
114
|
+
params.runtime.log(`- appSecret: ${redactValue(appSecret, { keepStart: 3, keepEnd: 3 })}`);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
117
|
+
params.runtime.error(`openclaw-baiduapp \u767B\u5F55\u914D\u7F6E\u5931\u8D25\uFF1A${message}`);
|
|
118
|
+
throw error;
|
|
119
|
+
} finally {
|
|
120
|
+
prompter.close();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
var init_login = __esm({
|
|
124
|
+
"src/auth/login.ts"() {
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
17
128
|
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
|
|
18
129
|
var external_exports = {};
|
|
19
130
|
__export(external_exports, {
|
|
@@ -4056,14 +4167,13 @@ var NEVER = INVALID;
|
|
|
4056
4167
|
|
|
4057
4168
|
// src/config.ts
|
|
4058
4169
|
var DEFAULT_ACCOUNT_ID = "default";
|
|
4170
|
+
var DEFAULT_AGENT_ID = "main";
|
|
4059
4171
|
var DEFAULT_API_BASE = "https://claw.baidu.com";
|
|
4060
4172
|
var BaiduAppAccountSchema = external_exports.object({
|
|
4061
4173
|
name: external_exports.string().optional(),
|
|
4062
4174
|
enabled: external_exports.boolean().optional(),
|
|
4063
4175
|
pollingEnabled: external_exports.boolean().optional(),
|
|
4064
4176
|
webhookPath: external_exports.string().optional(),
|
|
4065
|
-
token: external_exports.string().optional(),
|
|
4066
|
-
encodingAESKey: external_exports.string().optional(),
|
|
4067
4177
|
appKey: external_exports.string().optional(),
|
|
4068
4178
|
appSecret: external_exports.string().optional(),
|
|
4069
4179
|
apiBase: external_exports.string().optional(),
|
|
@@ -4082,8 +4192,6 @@ var BaiduAppConfigJsonSchema = {
|
|
|
4082
4192
|
enabled: { type: "boolean" },
|
|
4083
4193
|
pollingEnabled: { type: "boolean" },
|
|
4084
4194
|
webhookPath: { type: "string" },
|
|
4085
|
-
token: { type: "string" },
|
|
4086
|
-
encodingAESKey: { type: "string" },
|
|
4087
4195
|
appKey: { type: "string" },
|
|
4088
4196
|
appSecret: { type: "string" },
|
|
4089
4197
|
apiBase: { type: "string" },
|
|
@@ -4099,8 +4207,6 @@ var BaiduAppConfigJsonSchema = {
|
|
|
4099
4207
|
enabled: { type: "boolean" },
|
|
4100
4208
|
pollingEnabled: { type: "boolean" },
|
|
4101
4209
|
webhookPath: { type: "string" },
|
|
4102
|
-
token: { type: "string" },
|
|
4103
|
-
encodingAESKey: { type: "string" },
|
|
4104
4210
|
appKey: { type: "string" },
|
|
4105
4211
|
appSecret: { type: "string" },
|
|
4106
4212
|
apiBase: { type: "string" },
|
|
@@ -4115,6 +4221,10 @@ function normalizeAccountId(raw) {
|
|
|
4115
4221
|
const trimmed = String(raw ?? "").trim();
|
|
4116
4222
|
return trimmed || DEFAULT_ACCOUNT_ID;
|
|
4117
4223
|
}
|
|
4224
|
+
function extractAgentId(msg) {
|
|
4225
|
+
const raw = msg.agentid ?? "";
|
|
4226
|
+
return raw.trim() || DEFAULT_AGENT_ID;
|
|
4227
|
+
}
|
|
4118
4228
|
function listConfiguredAccountIds(cfg) {
|
|
4119
4229
|
const accounts = cfg.channels?.["openclaw-baiduapp"]?.accounts;
|
|
4120
4230
|
if (!accounts || typeof accounts !== "object") {
|
|
@@ -4162,12 +4272,10 @@ function resolveBaiduAppAccount(params) {
|
|
|
4162
4272
|
const merged = mergeBaiduAppAccountConfig(params.cfg, accountId);
|
|
4163
4273
|
const enabled = baseEnabled && merged.enabled !== false;
|
|
4164
4274
|
const isDefaultAccount = accountId === DEFAULT_ACCOUNT_ID;
|
|
4165
|
-
const token = merged.token?.trim() || (isDefaultAccount ? process.env.BAIDU_APP_TOKEN?.trim() : void 0) || void 0;
|
|
4166
|
-
const encodingAESKey = merged.encodingAESKey?.trim() || (isDefaultAccount ? process.env.BAIDU_APP_ENCODING_AES_KEY?.trim() : void 0) || void 0;
|
|
4167
4275
|
const appKey = merged.appKey?.trim() || (isDefaultAccount ? process.env.BAIDU_APP_KEY?.trim() : void 0) || void 0;
|
|
4168
4276
|
const appSecret = merged.appSecret?.trim() || (isDefaultAccount ? process.env.BAIDU_APP_SECRET?.trim() : void 0) || void 0;
|
|
4169
|
-
const configured = Boolean(
|
|
4170
|
-
const canSendActive = Boolean(appKey && appSecret
|
|
4277
|
+
const configured = Boolean(appKey && appSecret);
|
|
4278
|
+
const canSendActive = Boolean(appKey && appSecret);
|
|
4171
4279
|
const rawApiBase = merged.apiBase?.trim() || (isDefaultAccount ? process.env.BAIDU_API_BASE?.trim() : void 0) || void 0;
|
|
4172
4280
|
const apiBase = (rawApiBase || DEFAULT_API_BASE).replace(/\/+$/, "");
|
|
4173
4281
|
return {
|
|
@@ -4175,8 +4283,6 @@ function resolveBaiduAppAccount(params) {
|
|
|
4175
4283
|
name: merged.name?.trim() || void 0,
|
|
4176
4284
|
enabled,
|
|
4177
4285
|
configured,
|
|
4178
|
-
token,
|
|
4179
|
-
encodingAESKey,
|
|
4180
4286
|
appKey,
|
|
4181
4287
|
appSecret,
|
|
4182
4288
|
apiBase,
|
|
@@ -4184,6 +4290,37 @@ function resolveBaiduAppAccount(params) {
|
|
|
4184
4290
|
config: merged
|
|
4185
4291
|
};
|
|
4186
4292
|
}
|
|
4293
|
+
function resolveAgentField(agentCfg, mainCfg, baseAccount, field) {
|
|
4294
|
+
return agentCfg?.[field]?.trim() || mainCfg?.[field]?.trim() || baseAccount[field];
|
|
4295
|
+
}
|
|
4296
|
+
function resolveAgentAccount(params) {
|
|
4297
|
+
const { baseAccount, cfg, agentId } = params;
|
|
4298
|
+
if (agentId === baseAccount.accountId) {
|
|
4299
|
+
return baseAccount;
|
|
4300
|
+
}
|
|
4301
|
+
const accounts = cfg.channels?.["openclaw-baiduapp"]?.accounts;
|
|
4302
|
+
const agentCfg = accounts?.[agentId] && typeof accounts[agentId] === "object" ? accounts[agentId] : void 0;
|
|
4303
|
+
const mainCfg = agentId !== DEFAULT_AGENT_ID && accounts?.[DEFAULT_AGENT_ID] && typeof accounts[DEFAULT_AGENT_ID] === "object" ? accounts[DEFAULT_AGENT_ID] : void 0;
|
|
4304
|
+
const appKey = resolveAgentField(agentCfg, mainCfg, baseAccount, "appKey");
|
|
4305
|
+
const appSecret = resolveAgentField(agentCfg, mainCfg, baseAccount, "appSecret");
|
|
4306
|
+
const apiBase = baseAccount.apiBase;
|
|
4307
|
+
const name = resolveAgentField(agentCfg, mainCfg, baseAccount, "name");
|
|
4308
|
+
const configured = Boolean(appKey && appSecret);
|
|
4309
|
+
const canSendActive = Boolean(appKey && appSecret);
|
|
4310
|
+
const agentEnabled = agentCfg?.enabled !== false;
|
|
4311
|
+
return {
|
|
4312
|
+
...baseAccount,
|
|
4313
|
+
accountId: agentId,
|
|
4314
|
+
name: name || baseAccount.name,
|
|
4315
|
+
enabled: agentEnabled && baseAccount.enabled,
|
|
4316
|
+
configured,
|
|
4317
|
+
appKey,
|
|
4318
|
+
appSecret,
|
|
4319
|
+
apiBase,
|
|
4320
|
+
canSendActive,
|
|
4321
|
+
config: { ...baseAccount.config, ...mainCfg ?? {}, ...agentCfg ?? {} }
|
|
4322
|
+
};
|
|
4323
|
+
}
|
|
4187
4324
|
|
|
4188
4325
|
// src/shared/logger.ts
|
|
4189
4326
|
function createLogger(prefix, opts) {
|
|
@@ -4196,86 +4333,27 @@ function createLogger(prefix, opts) {
|
|
|
4196
4333
|
error: (msg) => errorFn(`[${prefix}] [ERROR] ${msg}`)
|
|
4197
4334
|
};
|
|
4198
4335
|
}
|
|
4199
|
-
function decodeEncodingAESKey(encodingAESKey) {
|
|
4200
|
-
const trimmed = encodingAESKey.trim();
|
|
4201
|
-
if (!trimmed) {
|
|
4202
|
-
throw new Error("encodingAESKey missing");
|
|
4203
|
-
}
|
|
4204
|
-
const withPadding = trimmed.endsWith("=") ? trimmed : `${trimmed}=`;
|
|
4205
|
-
const key = Buffer.from(withPadding, "base64");
|
|
4206
|
-
if (key.length !== 32) {
|
|
4207
|
-
throw new Error(`invalid encodingAESKey (expected 32 bytes after base64 decode, got ${key.length})`);
|
|
4208
|
-
}
|
|
4209
|
-
return key;
|
|
4210
|
-
}
|
|
4211
|
-
var PKCS7_BLOCK_SIZE = 32;
|
|
4212
|
-
function pkcs7Pad(buf, blockSize) {
|
|
4213
|
-
const mod = buf.length % blockSize;
|
|
4214
|
-
const pad = mod === 0 ? blockSize : blockSize - mod;
|
|
4215
|
-
return Buffer.concat([buf, Buffer.alloc(pad, pad)]);
|
|
4216
|
-
}
|
|
4217
|
-
function pkcs7Unpad(buf, blockSize) {
|
|
4218
|
-
if (buf.length === 0) {
|
|
4219
|
-
throw new Error("invalid pkcs7 payload");
|
|
4220
|
-
}
|
|
4221
|
-
const pad = buf[buf.length - 1];
|
|
4222
|
-
if (!pad || pad < 1 || pad > blockSize || pad > buf.length) {
|
|
4223
|
-
throw new Error("invalid pkcs7 padding");
|
|
4224
|
-
}
|
|
4225
|
-
for (let i = 1; i <= pad; i += 1) {
|
|
4226
|
-
if (buf[buf.length - i] !== pad) {
|
|
4227
|
-
throw new Error("invalid pkcs7 padding");
|
|
4228
|
-
}
|
|
4229
|
-
}
|
|
4230
|
-
return buf.subarray(0, buf.length - pad);
|
|
4231
|
-
}
|
|
4232
4336
|
function sha1Hex(input) {
|
|
4233
|
-
return
|
|
4337
|
+
return crypto2.createHash("sha1").update(input).digest("hex");
|
|
4234
4338
|
}
|
|
4235
|
-
function
|
|
4236
|
-
|
|
4237
|
-
return sha1Hex(parts.join(""));
|
|
4339
|
+
function computeAKSKBearerToken(params) {
|
|
4340
|
+
return sha1Hex(params.ak + params.sk + params.timestamp + params.nonce);
|
|
4238
4341
|
}
|
|
4239
|
-
function
|
|
4240
|
-
const expected =
|
|
4241
|
-
|
|
4342
|
+
function verifyAKSKBearerToken(params) {
|
|
4343
|
+
const expected = computeAKSKBearerToken({
|
|
4344
|
+
ak: params.ak,
|
|
4345
|
+
sk: params.sk,
|
|
4242
4346
|
timestamp: params.timestamp,
|
|
4243
|
-
nonce: params.nonce
|
|
4244
|
-
encrypt: params.encrypt
|
|
4347
|
+
nonce: params.nonce
|
|
4245
4348
|
});
|
|
4246
|
-
return expected === params.
|
|
4349
|
+
return expected === params.token;
|
|
4247
4350
|
}
|
|
4248
|
-
function
|
|
4249
|
-
|
|
4250
|
-
const iv = aesKey.subarray(0, 16);
|
|
4251
|
-
const decipher = crypto3.createDecipheriv("aes-256-cbc", aesKey, iv);
|
|
4252
|
-
decipher.setAutoPadding(false);
|
|
4253
|
-
const decryptedPadded = Buffer.concat([decipher.update(Buffer.from(params.encrypt, "base64")), decipher.final()]);
|
|
4254
|
-
const decrypted = pkcs7Unpad(decryptedPadded, PKCS7_BLOCK_SIZE);
|
|
4255
|
-
if (decrypted.length < 20) {
|
|
4256
|
-
throw new Error(`invalid decrypted payload (expected at least 20 bytes, got ${decrypted.length})`);
|
|
4257
|
-
}
|
|
4258
|
-
const msgLen = decrypted.readUInt32BE(16);
|
|
4259
|
-
const msgStart = 20;
|
|
4260
|
-
const msgEnd = msgStart + msgLen;
|
|
4261
|
-
if (msgEnd > decrypted.length) {
|
|
4262
|
-
throw new Error(`invalid decrypted msg length (msgEnd=${msgEnd}, payloadLength=${decrypted.length})`);
|
|
4263
|
-
}
|
|
4264
|
-
return decrypted.subarray(msgStart, msgEnd).toString("utf8");
|
|
4351
|
+
function generateNonce() {
|
|
4352
|
+
return crypto2.randomBytes(8).toString("hex");
|
|
4265
4353
|
}
|
|
4266
|
-
function
|
|
4267
|
-
const
|
|
4268
|
-
|
|
4269
|
-
const random16 = crypto3.randomBytes(16);
|
|
4270
|
-
const msg = Buffer.from(params.plaintext ?? "", "utf8");
|
|
4271
|
-
const msgLen = Buffer.alloc(4);
|
|
4272
|
-
msgLen.writeUInt32BE(msg.length, 0);
|
|
4273
|
-
const raw = Buffer.concat([random16, msgLen, msg]);
|
|
4274
|
-
const padded = pkcs7Pad(raw, PKCS7_BLOCK_SIZE);
|
|
4275
|
-
const cipher = crypto3.createCipheriv("aes-256-cbc", aesKey, iv);
|
|
4276
|
-
cipher.setAutoPadding(false);
|
|
4277
|
-
const encrypted = Buffer.concat([cipher.update(padded), cipher.final()]);
|
|
4278
|
-
return encrypted.toString("base64");
|
|
4354
|
+
function buildAuthorizationHeader(params) {
|
|
4355
|
+
const token = computeAKSKBearerToken(params);
|
|
4356
|
+
return `Bearer ${token}`;
|
|
4279
4357
|
}
|
|
4280
4358
|
var require2 = createRequire(import.meta.url);
|
|
4281
4359
|
var pkg = require2("../package.json");
|
|
@@ -4283,48 +4361,54 @@ var PLUGIN_VERSION = pkg.version;
|
|
|
4283
4361
|
|
|
4284
4362
|
// src/api.ts
|
|
4285
4363
|
var logger = createLogger("openclaw-baiduapp");
|
|
4364
|
+
var DEFAULT_sessionId = "agent:main:main";
|
|
4286
4365
|
async function sendBaiduAppMessage(account, message, options) {
|
|
4287
4366
|
if (!account.canSendActive) {
|
|
4288
|
-
logger.error("Account not configured for active sending (missing appKey
|
|
4367
|
+
logger.error("Account not configured for active sending (missing appKey or appSecret)");
|
|
4289
4368
|
return {
|
|
4290
4369
|
ok: false,
|
|
4291
4370
|
errcode: -1,
|
|
4292
|
-
errmsg: "Account not configured for active sending (missing appKey
|
|
4371
|
+
errmsg: "Account not configured for active sending (missing appKey or appSecret)"
|
|
4293
4372
|
};
|
|
4294
4373
|
}
|
|
4295
4374
|
const normalizedPayload = typeof message === "string" ? {
|
|
4296
|
-
|
|
4297
|
-
|
|
4375
|
+
list: [{
|
|
4376
|
+
type: "text",
|
|
4377
|
+
data: {
|
|
4378
|
+
text: { content: message }
|
|
4379
|
+
}
|
|
4380
|
+
}]
|
|
4298
4381
|
} : message;
|
|
4299
|
-
const
|
|
4300
|
-
|
|
4382
|
+
const sessionId = options?.sessionId ?? DEFAULT_sessionId;
|
|
4383
|
+
const callbackBody = {
|
|
4384
|
+
sessionId,
|
|
4385
|
+
list: normalizedPayload.list,
|
|
4301
4386
|
version: PLUGIN_VERSION,
|
|
4302
|
-
|
|
4303
|
-
...options?.
|
|
4304
|
-
...options?.chunkKey != null ? { chunkKey: options.chunkKey } : {}
|
|
4387
|
+
isActive: options?.isActive || false,
|
|
4388
|
+
...options?.agentid ? { agentid: options.agentid } : {},
|
|
4389
|
+
...options?.chunkKey != null ? { chunkKey: options.chunkKey } : {},
|
|
4390
|
+
...options?.replyToMsgId ? { replyToMsgId: options.replyToMsgId } : {}
|
|
4305
4391
|
};
|
|
4306
|
-
const plaintext = JSON.stringify(payload);
|
|
4307
|
-
const encrypt = encryptBaiduAppPlaintext({
|
|
4308
|
-
encodingAESKey: account.encodingAESKey ?? "",
|
|
4309
|
-
plaintext
|
|
4310
|
-
});
|
|
4311
4392
|
const timestamp = String(Math.floor(Date.now() / 1e3));
|
|
4312
|
-
const nonce =
|
|
4313
|
-
const
|
|
4314
|
-
|
|
4393
|
+
const nonce = generateNonce();
|
|
4394
|
+
const authorization = buildAuthorizationHeader({
|
|
4395
|
+
ak: account.appKey ?? "",
|
|
4396
|
+
sk: account.appSecret ?? "",
|
|
4315
4397
|
timestamp,
|
|
4316
|
-
nonce
|
|
4317
|
-
encrypt
|
|
4398
|
+
nonce
|
|
4318
4399
|
});
|
|
4319
|
-
const sendMessageUrl = `${account.apiBase}/
|
|
4320
|
-
const url = `${sendMessageUrl}?timestamp=${encodeURIComponent(timestamp)}&ak=${encodeURIComponent(account.appKey ?? "")}&nonce=${encodeURIComponent(nonce)}
|
|
4321
|
-
const body = JSON.stringify(
|
|
4400
|
+
const sendMessageUrl = `${account.apiBase}/channel/msg/callback`;
|
|
4401
|
+
const url = `${sendMessageUrl}?timestamp=${encodeURIComponent(timestamp)}&ak=${encodeURIComponent(account.appKey ?? "")}&nonce=${encodeURIComponent(nonce)}`;
|
|
4402
|
+
const body = JSON.stringify(callbackBody);
|
|
4322
4403
|
logger.info(`POST ${url}`);
|
|
4323
4404
|
logger.debug(`request body: ${body}`);
|
|
4324
4405
|
const resp = await fetch(url, {
|
|
4325
4406
|
method: "POST",
|
|
4326
4407
|
body,
|
|
4327
|
-
headers: {
|
|
4408
|
+
headers: {
|
|
4409
|
+
"Authorization": authorization,
|
|
4410
|
+
"Content-Type": "application/json"
|
|
4411
|
+
}
|
|
4328
4412
|
});
|
|
4329
4413
|
const text = await resp.text();
|
|
4330
4414
|
if (!text) {
|
|
@@ -4365,21 +4449,21 @@ function buildMediaPayload(mediaList, opts) {
|
|
|
4365
4449
|
|
|
4366
4450
|
// src/bot.ts
|
|
4367
4451
|
function extractBaiduAppTextContent(msg) {
|
|
4368
|
-
const msgtype = String(msg.msgtype ??
|
|
4452
|
+
const msgtype = String(msg.msgtype ?? "").toLowerCase();
|
|
4369
4453
|
if (msgtype === "text") {
|
|
4370
|
-
const content = msg.text?.content
|
|
4454
|
+
const content = msg.text?.content;
|
|
4371
4455
|
return typeof content === "string" ? content : "";
|
|
4372
4456
|
}
|
|
4373
4457
|
if (msgtype === "event") {
|
|
4374
4458
|
const eventtype = String(
|
|
4375
|
-
msg.event?.eventtype ??
|
|
4459
|
+
msg.event?.eventtype ?? ""
|
|
4376
4460
|
).trim();
|
|
4377
4461
|
return eventtype ? `[event] ${eventtype}` : "[event]";
|
|
4378
4462
|
}
|
|
4379
4463
|
return msgtype ? `[${msgtype}]` : "";
|
|
4380
4464
|
}
|
|
4381
4465
|
function canDispatchBaiduAppInboundMessage(msg) {
|
|
4382
|
-
const msgtype = String(msg.msgtype ??
|
|
4466
|
+
const msgtype = String(msg.msgtype ?? "").toLowerCase();
|
|
4383
4467
|
if (msgtype === "text") {
|
|
4384
4468
|
if (extractBaiduAppTextContent(msg)) {
|
|
4385
4469
|
return true;
|
|
@@ -4449,7 +4533,7 @@ async function dispatchBaiduAppMessage(params) {
|
|
|
4449
4533
|
cfg: safeCfg,
|
|
4450
4534
|
channel: "openclaw-baiduapp",
|
|
4451
4535
|
accountId: account.accountId,
|
|
4452
|
-
peer: { kind: "dm", id:
|
|
4536
|
+
peer: { kind: "dm", id: account.accountId || DEFAULT_AGENT_ID }
|
|
4453
4537
|
});
|
|
4454
4538
|
logger3.info(`SessionKey: ${route.sessionKey}`);
|
|
4455
4539
|
logger3.info(
|
|
@@ -4479,7 +4563,7 @@ async function dispatchBaiduAppMessage(params) {
|
|
|
4479
4563
|
envelope: envelopeOptions,
|
|
4480
4564
|
body: rawBody
|
|
4481
4565
|
}) : rawBody;
|
|
4482
|
-
const msgid = msg.msgid ??
|
|
4566
|
+
const msgid = msg.msgid ?? void 0;
|
|
4483
4567
|
const ctxPayload = channel.reply?.finalizeInboundContext ? channel.reply.finalizeInboundContext({
|
|
4484
4568
|
Body: body,
|
|
4485
4569
|
RawBody: rawBody,
|
|
@@ -4685,7 +4769,7 @@ var require3 = createRequire(import.meta.url);
|
|
|
4685
4769
|
var BaiduCloudSdk = require3("@baiducloud/sdk");
|
|
4686
4770
|
var DefaultBosClient = BaiduCloudSdk.BosClient;
|
|
4687
4771
|
var MAX_DOWNLOAD_REDIRECTS = 5;
|
|
4688
|
-
var EMPTY_QUERY_MD5 =
|
|
4772
|
+
var EMPTY_QUERY_MD5 = crypto2.createHash("md5").update("").digest("hex");
|
|
4689
4773
|
var SKS_BASE_TOKEN_POSITIONS = [12, 37, 5, 23, 48, 15, 62, 33];
|
|
4690
4774
|
async function fetchSksCredentials(account, deps = {}) {
|
|
4691
4775
|
if (!account.appKey?.trim()) {
|
|
@@ -4699,7 +4783,7 @@ async function fetchSksCredentials(account, deps = {}) {
|
|
|
4699
4783
|
const pageLid = deps.createPageLid?.() ?? generateSksPageLid();
|
|
4700
4784
|
const timestamp = String((deps.now?.() ?? /* @__PURE__ */ new Date()).getTime());
|
|
4701
4785
|
const token = createSksRequestToken({ pageLid, timestamp });
|
|
4702
|
-
const url = `${apiBase}/file/sts?ak=${encodeURIComponent(account.appKey)}&sk=${encodeURIComponent(account.appSecret)}&tk=${encodeURIComponent(token)}`;
|
|
4786
|
+
const url = `${apiBase}/channel/file/sts?ak=${encodeURIComponent(account.appKey)}&sk=${encodeURIComponent(account.appSecret)}&tk=${encodeURIComponent(token)}`;
|
|
4703
4787
|
const response = await fetchImpl(url, { method: "POST" });
|
|
4704
4788
|
if (!response.ok) {
|
|
4705
4789
|
throw new Error(`SKS request failed with HTTP ${response.status}`);
|
|
@@ -4888,10 +4972,10 @@ function parseSksResponse(payload) {
|
|
|
4888
4972
|
};
|
|
4889
4973
|
}
|
|
4890
4974
|
function generateSksPageLid() {
|
|
4891
|
-
return
|
|
4975
|
+
return crypto2.randomBytes(16).toString("hex");
|
|
4892
4976
|
}
|
|
4893
4977
|
function createSksBaseToken(pageLid) {
|
|
4894
|
-
const pageLidHash =
|
|
4978
|
+
const pageLidHash = crypto2.createHash("sha256").update(pageLid).digest("hex");
|
|
4895
4979
|
const characters = SKS_BASE_TOKEN_POSITIONS.map((position) => {
|
|
4896
4980
|
const character = pageLidHash[position];
|
|
4897
4981
|
if (!character) {
|
|
@@ -4950,7 +5034,7 @@ function assertSafeUntrustedFileName(fileName) {
|
|
|
4950
5034
|
}
|
|
4951
5035
|
function buildBosObjectKey(params) {
|
|
4952
5036
|
const timestamp = formatUtcDate(params.now?.() ?? /* @__PURE__ */ new Date());
|
|
4953
|
-
const uniqueId =
|
|
5037
|
+
const uniqueId = crypto2.randomUUID();
|
|
4954
5038
|
return `${params.prefixPath}/${timestamp}/${uniqueId}-${params.fileName}`;
|
|
4955
5039
|
}
|
|
4956
5040
|
function formatUtcDate(date) {
|
|
@@ -5083,7 +5167,7 @@ function resolveDownloadFileName(params) {
|
|
|
5083
5167
|
}
|
|
5084
5168
|
function buildTempFilePath(params) {
|
|
5085
5169
|
const timestamp = (params.now?.() ?? /* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
5086
|
-
return path2.join(params.tempDir, `${timestamp}-${
|
|
5170
|
+
return path2.join(params.tempDir, `${timestamp}-${crypto2.randomUUID()}-${params.fileName}`);
|
|
5087
5171
|
}
|
|
5088
5172
|
async function ensurePluginTempDir(resolveTmpDir) {
|
|
5089
5173
|
const baseTmpDir = resolveTmpDir?.() ?? resolvePreferredOpenClawTmpDir();
|
|
@@ -5144,12 +5228,12 @@ function normalizeWebhookPath(raw) {
|
|
|
5144
5228
|
function jsonOk(res, body) {
|
|
5145
5229
|
res.statusCode = 200;
|
|
5146
5230
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
5147
|
-
res.end(JSON.stringify({
|
|
5231
|
+
res.end(JSON.stringify({ code: 0, msg: "success", data: body }));
|
|
5148
5232
|
}
|
|
5149
5233
|
function jsonError(res, message, statusCode = 200) {
|
|
5150
5234
|
res.statusCode = statusCode;
|
|
5151
5235
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
5152
|
-
res.end(JSON.stringify({
|
|
5236
|
+
res.end(JSON.stringify({ code: -1, msg: message, data: {} }));
|
|
5153
5237
|
}
|
|
5154
5238
|
async function readRawBody(req, maxBytes) {
|
|
5155
5239
|
const chunks = [];
|
|
@@ -5181,47 +5265,6 @@ async function readRawBody(req, maxBytes) {
|
|
|
5181
5265
|
});
|
|
5182
5266
|
});
|
|
5183
5267
|
}
|
|
5184
|
-
function parseXmlBody(xml) {
|
|
5185
|
-
const result = {};
|
|
5186
|
-
const cdataRegex = /<(\w+)><!\[CDATA\[([\s\S]*?)\]\]><\/\1>/g;
|
|
5187
|
-
let match;
|
|
5188
|
-
while ((match = cdataRegex.exec(xml)) !== null) {
|
|
5189
|
-
const [, key = "", value = ""] = match;
|
|
5190
|
-
result[key] = value;
|
|
5191
|
-
}
|
|
5192
|
-
const simpleRegex = /<(\w+)>([^<]*)<\/\1>/g;
|
|
5193
|
-
while ((match = simpleRegex.exec(xml)) !== null) {
|
|
5194
|
-
const [, key = "", value = ""] = match;
|
|
5195
|
-
if (!result[key]) {
|
|
5196
|
-
result[key] = value;
|
|
5197
|
-
}
|
|
5198
|
-
}
|
|
5199
|
-
return result;
|
|
5200
|
-
}
|
|
5201
|
-
function isXmlFormat(raw) {
|
|
5202
|
-
const trimmed = raw.trim();
|
|
5203
|
-
return trimmed.startsWith("<") && trimmed.endsWith(">");
|
|
5204
|
-
}
|
|
5205
|
-
function buildEncryptedJsonReply(params) {
|
|
5206
|
-
const base = params.plaintextJson != null && typeof params.plaintextJson === "object" ? params.plaintextJson : {};
|
|
5207
|
-
const plaintext = JSON.stringify({ ...base, version: PLUGIN_VERSION });
|
|
5208
|
-
const encrypt = encryptBaiduAppPlaintext({
|
|
5209
|
-
encodingAESKey: params.account.encodingAESKey ?? "",
|
|
5210
|
-
plaintext
|
|
5211
|
-
});
|
|
5212
|
-
const msgsignature = computeBaiduAppMsgSignature({
|
|
5213
|
-
token: params.account.token ?? "",
|
|
5214
|
-
timestamp: params.timestamp,
|
|
5215
|
-
nonce: params.nonce,
|
|
5216
|
-
encrypt
|
|
5217
|
-
});
|
|
5218
|
-
return {
|
|
5219
|
-
encrypt,
|
|
5220
|
-
msgsignature,
|
|
5221
|
-
timestamp: params.timestamp,
|
|
5222
|
-
nonce: params.nonce
|
|
5223
|
-
};
|
|
5224
|
-
}
|
|
5225
5268
|
function resolveQueryParams(req) {
|
|
5226
5269
|
const url = new URL(req.url ?? "/", "http://localhost");
|
|
5227
5270
|
return url.searchParams;
|
|
@@ -5230,8 +5273,16 @@ function resolvePath(req) {
|
|
|
5230
5273
|
const url = new URL(req.url ?? "/", "http://localhost");
|
|
5231
5274
|
return normalizeWebhookPath(url.pathname || "/");
|
|
5232
5275
|
}
|
|
5233
|
-
function
|
|
5234
|
-
|
|
5276
|
+
function resolveBearerToken(req) {
|
|
5277
|
+
const authorization = req.headers.authorization ?? req.headers.Authorization;
|
|
5278
|
+
if (Array.isArray(authorization)) {
|
|
5279
|
+
return "";
|
|
5280
|
+
}
|
|
5281
|
+
const value = typeof authorization === "string" ? authorization.trim() : "";
|
|
5282
|
+
if (!value.toLowerCase().startsWith("bearer ")) {
|
|
5283
|
+
return "";
|
|
5284
|
+
}
|
|
5285
|
+
return value.slice(7).trim();
|
|
5235
5286
|
}
|
|
5236
5287
|
function buildLogger(target) {
|
|
5237
5288
|
return createLogger("openclaw-baiduapp", {
|
|
@@ -5299,50 +5350,49 @@ async function downloadInboundFiles(params) {
|
|
|
5299
5350
|
}
|
|
5300
5351
|
};
|
|
5301
5352
|
}
|
|
5302
|
-
function
|
|
5303
|
-
const
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5353
|
+
function parseV2MsgToInbound(inner, outer) {
|
|
5354
|
+
const list = Array.isArray(inner.list) ? inner.list : [];
|
|
5355
|
+
const textItem = list.find(
|
|
5356
|
+
(item) => item && typeof item === "object" && item.type === "text"
|
|
5357
|
+
);
|
|
5358
|
+
const fileItems = list.filter(
|
|
5359
|
+
(item) => item && typeof item === "object" && item.type === "file"
|
|
5360
|
+
);
|
|
5361
|
+
const textContent = textItem?.data?.text?.content ?? "";
|
|
5362
|
+
const files = fileItems.map((f) => ({ url: f.data.file_id, fileType: "file" }));
|
|
5363
|
+
return {
|
|
5364
|
+
msgtype: "text",
|
|
5365
|
+
msgid: typeof outer.msgid === "string" ? outer.msgid : void 0,
|
|
5366
|
+
agentid: typeof outer.agentid === "string" ? outer.agentid : void 0,
|
|
5367
|
+
text: textContent ? { content: textContent } : void 0,
|
|
5368
|
+
...files.length > 0 ? { files } : {}
|
|
5369
|
+
};
|
|
5370
|
+
}
|
|
5371
|
+
function parseBaiduAppCandidates(params) {
|
|
5372
|
+
const results = [];
|
|
5373
|
+
let outer = {};
|
|
5320
5374
|
try {
|
|
5321
|
-
const parsed = JSON.parse(
|
|
5322
|
-
if (
|
|
5323
|
-
|
|
5375
|
+
const parsed = JSON.parse(params.raw);
|
|
5376
|
+
if (parsed && typeof parsed === "object") {
|
|
5377
|
+
outer = parsed;
|
|
5324
5378
|
}
|
|
5325
|
-
return parsed;
|
|
5326
5379
|
} catch {
|
|
5327
|
-
|
|
5380
|
+
outer = {};
|
|
5328
5381
|
}
|
|
5329
|
-
}
|
|
5330
|
-
|
|
5331
|
-
const results = [];
|
|
5332
|
-
for (const candidate of params.candidates) {
|
|
5333
|
-
if (!candidate.account.encodingAESKey) {
|
|
5334
|
-
continue;
|
|
5335
|
-
}
|
|
5382
|
+
let inner = {};
|
|
5383
|
+
if (typeof outer.msg === "string") {
|
|
5336
5384
|
try {
|
|
5337
|
-
const
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
}
|
|
5341
|
-
const msg = parseBaiduAppPlainMessage(plaintext);
|
|
5342
|
-
results.push({ target: candidate, plaintext, msg });
|
|
5385
|
+
const parsedInner = JSON.parse(outer.msg);
|
|
5386
|
+
if (parsedInner && typeof parsedInner === "object") {
|
|
5387
|
+
inner = parsedInner;
|
|
5388
|
+
}
|
|
5343
5389
|
} catch {
|
|
5390
|
+
inner = {};
|
|
5344
5391
|
}
|
|
5345
5392
|
}
|
|
5393
|
+
for (const candidate of params.candidates) {
|
|
5394
|
+
results.push({ target: candidate, msg: parseV2MsgToInbound(inner, outer) });
|
|
5395
|
+
}
|
|
5346
5396
|
return results;
|
|
5347
5397
|
}
|
|
5348
5398
|
function selectDecryptedTarget(params) {
|
|
@@ -5359,8 +5409,9 @@ async function processBaiduAppInboundMessage(params) {
|
|
|
5359
5409
|
const { target, msg } = params;
|
|
5360
5410
|
const logger3 = buildLogger(target);
|
|
5361
5411
|
target.statusSink?.({ lastInboundAt: Date.now() });
|
|
5362
|
-
const msgtype = String(msg.msgtype ??
|
|
5363
|
-
const msgid = msg.msgid
|
|
5412
|
+
const msgtype = String(msg.msgtype ?? "").toLowerCase();
|
|
5413
|
+
const msgid = msg.msgid ? String(msg.msgid) : void 0;
|
|
5414
|
+
const agentId = extractAgentId(msg);
|
|
5364
5415
|
logger3.info(`inbound: type=${msgtype || "unknown"} msgid=${msgid ?? "none"} account=${target.account.accountId}`);
|
|
5365
5416
|
if (!canDispatchBaiduAppInboundMessage(msg)) {
|
|
5366
5417
|
logger3.warn(`inbound message skipped: type=${msgtype || "unknown"} reason=no-dispatchable-content`);
|
|
@@ -5368,6 +5419,11 @@ async function processBaiduAppInboundMessage(params) {
|
|
|
5368
5419
|
}
|
|
5369
5420
|
const inboundFileResult = msgtype === "text" ? await downloadInboundFiles({ msg, logger: logger3, runtime: target.runtime }) : { localFiles: [], diagnostic: {} };
|
|
5370
5421
|
const inboundMediaFiles = inboundFileResult.localFiles;
|
|
5422
|
+
const agentAccount = resolveAgentAccount({
|
|
5423
|
+
baseAccount: target.account,
|
|
5424
|
+
cfg: target.config,
|
|
5425
|
+
agentId
|
|
5426
|
+
});
|
|
5371
5427
|
const core = tryGetBaiduAppRuntime();
|
|
5372
5428
|
if (core) {
|
|
5373
5429
|
logger3.info(`agent dispatch started: canSendActive=${target.account.canSendActive}`);
|
|
@@ -5380,8 +5436,9 @@ async function processBaiduAppInboundMessage(params) {
|
|
|
5380
5436
|
);
|
|
5381
5437
|
target.statusSink?.({ lastOutboundAt: Date.now() });
|
|
5382
5438
|
if (target.account.canSendActive) {
|
|
5383
|
-
sendBaiduAppMessage(
|
|
5384
|
-
msgid,
|
|
5439
|
+
sendBaiduAppMessage(agentAccount, text, {
|
|
5440
|
+
replyToMsgId: msgid,
|
|
5441
|
+
agentid: agentId,
|
|
5385
5442
|
chunkKey: currentChunkKey
|
|
5386
5443
|
}).then((result) => {
|
|
5387
5444
|
if (!result.ok) {
|
|
@@ -5404,7 +5461,7 @@ async function processBaiduAppInboundMessage(params) {
|
|
|
5404
5461
|
};
|
|
5405
5462
|
dispatchBaiduAppMessage({
|
|
5406
5463
|
cfg: target.config,
|
|
5407
|
-
account:
|
|
5464
|
+
account: agentAccount,
|
|
5408
5465
|
msg,
|
|
5409
5466
|
core,
|
|
5410
5467
|
hooks,
|
|
@@ -5446,53 +5503,43 @@ async function handleBaiduAppWebhookRequest(req, res) {
|
|
|
5446
5503
|
const query = resolveQueryParams(req);
|
|
5447
5504
|
const timestamp = query.get("timestamp") ?? "";
|
|
5448
5505
|
const nonce = query.get("nonce") ?? "";
|
|
5449
|
-
const
|
|
5506
|
+
const ak = query.get("ak") ?? "";
|
|
5507
|
+
const token = resolveBearerToken(req);
|
|
5450
5508
|
const primary = targets[0];
|
|
5451
5509
|
const logger3 = buildLogger(primary);
|
|
5452
5510
|
if (req.method === "GET") {
|
|
5453
5511
|
const echostr = query.get("echostr") ?? "";
|
|
5454
|
-
if (!timestamp || !nonce || !
|
|
5512
|
+
if (!ak || !timestamp || !nonce || !token || !echostr) {
|
|
5455
5513
|
jsonError(res, "missing query params", 400);
|
|
5456
5514
|
return true;
|
|
5457
5515
|
}
|
|
5458
|
-
const
|
|
5459
|
-
if (!candidate.account.
|
|
5516
|
+
const tokenMatched2 = targets.filter((candidate) => {
|
|
5517
|
+
if (!candidate.account.appKey || !candidate.account.appSecret) {
|
|
5518
|
+
return false;
|
|
5519
|
+
}
|
|
5520
|
+
if (candidate.account.appKey !== ak) {
|
|
5460
5521
|
return false;
|
|
5461
5522
|
}
|
|
5462
|
-
return
|
|
5463
|
-
|
|
5523
|
+
return verifyAKSKBearerToken({
|
|
5524
|
+
ak: candidate.account.appKey,
|
|
5525
|
+
sk: candidate.account.appSecret,
|
|
5464
5526
|
timestamp,
|
|
5465
5527
|
nonce,
|
|
5466
|
-
|
|
5467
|
-
signature
|
|
5528
|
+
token
|
|
5468
5529
|
});
|
|
5469
5530
|
});
|
|
5470
|
-
if (
|
|
5471
|
-
jsonError(res, "unauthorized");
|
|
5472
|
-
return true;
|
|
5473
|
-
}
|
|
5474
|
-
const decryptable2 = signatureMatched2.filter((candidate) => Boolean(candidate.account.encodingAESKey));
|
|
5475
|
-
if (decryptable2.length === 0) {
|
|
5531
|
+
if (tokenMatched2.length === 0) {
|
|
5476
5532
|
jsonError(res, "unauthorized");
|
|
5477
5533
|
return true;
|
|
5478
5534
|
}
|
|
5479
|
-
|
|
5480
|
-
candidates: decryptable2,
|
|
5481
|
-
encrypt: echostr
|
|
5482
|
-
});
|
|
5483
|
-
if (decryptedCandidates2.length === 0) {
|
|
5484
|
-
jsonError(res, "decrypt failed");
|
|
5485
|
-
return true;
|
|
5486
|
-
}
|
|
5487
|
-
const selected2 = selectDecryptedTarget({ candidates: decryptedCandidates2, logger: logger3 });
|
|
5488
|
-
jsonOk(res, selected2.plaintext);
|
|
5535
|
+
jsonOk(res, echostr);
|
|
5489
5536
|
return true;
|
|
5490
5537
|
}
|
|
5491
5538
|
if (req.method !== "POST") {
|
|
5492
5539
|
jsonError(res, "Method Not Allowed", 405);
|
|
5493
5540
|
return true;
|
|
5494
5541
|
}
|
|
5495
|
-
if (!timestamp || !nonce || !
|
|
5542
|
+
if (!ak || !timestamp || !nonce || !token) {
|
|
5496
5543
|
jsonError(res, "missing query params");
|
|
5497
5544
|
return true;
|
|
5498
5545
|
}
|
|
@@ -5502,90 +5549,56 @@ async function handleBaiduAppWebhookRequest(req, res) {
|
|
|
5502
5549
|
return true;
|
|
5503
5550
|
}
|
|
5504
5551
|
const rawBody = body.raw;
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
encrypt = xmlData.Encrypt ?? "";
|
|
5512
|
-
msgSignature = xmlData.MsgSignature ?? signature;
|
|
5513
|
-
msgTimestamp = xmlData.TimeStamp ?? timestamp;
|
|
5514
|
-
msgNonce = xmlData.Nonce ?? nonce;
|
|
5515
|
-
logger3.info(`inbound xml parsed: hasEncrypt=${Boolean(encrypt)}, msg_signature=${msgSignature ? "yes" : "no"}`);
|
|
5516
|
-
} else {
|
|
5517
|
-
try {
|
|
5518
|
-
const record = JSON.parse(rawBody);
|
|
5519
|
-
encrypt = String(record.encrypt ?? record.Encrypt ?? "");
|
|
5520
|
-
logger3.info(`inbound json parsed: hasEncrypt=${Boolean(encrypt)}`);
|
|
5521
|
-
} catch {
|
|
5522
|
-
logger3.warn(`inbound payload parse failed: not valid xml or json`);
|
|
5523
|
-
jsonError(res, "invalid payload format");
|
|
5524
|
-
return true;
|
|
5525
|
-
}
|
|
5526
|
-
}
|
|
5527
|
-
if (!encrypt) {
|
|
5528
|
-
jsonError(res, "missing encrypt");
|
|
5552
|
+
try {
|
|
5553
|
+
JSON.parse(rawBody);
|
|
5554
|
+
logger3.info("inbound json parsed");
|
|
5555
|
+
} catch {
|
|
5556
|
+
logger3.warn("inbound payload parse failed: not valid json");
|
|
5557
|
+
jsonError(res, "invalid payload format");
|
|
5529
5558
|
return true;
|
|
5530
5559
|
}
|
|
5531
|
-
const
|
|
5532
|
-
if (!candidate.account.
|
|
5560
|
+
const tokenMatched = targets.filter((candidate) => {
|
|
5561
|
+
if (!candidate.account.appKey || !candidate.account.appSecret) {
|
|
5562
|
+
return false;
|
|
5563
|
+
}
|
|
5564
|
+
if (candidate.account.appKey !== ak) {
|
|
5533
5565
|
return false;
|
|
5534
5566
|
}
|
|
5535
|
-
return
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5567
|
+
return verifyAKSKBearerToken({
|
|
5568
|
+
ak: candidate.account.appKey,
|
|
5569
|
+
sk: candidate.account.appSecret,
|
|
5570
|
+
timestamp,
|
|
5571
|
+
nonce,
|
|
5572
|
+
token
|
|
5541
5573
|
});
|
|
5542
5574
|
});
|
|
5543
|
-
if (
|
|
5544
|
-
logger3.warn(`
|
|
5575
|
+
if (tokenMatched.length === 0) {
|
|
5576
|
+
logger3.warn(`bearer token verification failed: checked ${targets.length} account(s), none matched`);
|
|
5545
5577
|
jsonError(res, "unauthorized");
|
|
5546
5578
|
return true;
|
|
5547
5579
|
}
|
|
5548
|
-
logger3.debug(`
|
|
5549
|
-
const
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
jsonError(res, "openclaw-baiduapp not configured");
|
|
5553
|
-
return true;
|
|
5554
|
-
}
|
|
5555
|
-
const decryptedCandidates = decryptBaiduAppCandidates({
|
|
5556
|
-
candidates: decryptable,
|
|
5557
|
-
encrypt
|
|
5580
|
+
logger3.debug(`bearer token verified: ${tokenMatched.length} account(s) matched`);
|
|
5581
|
+
const decryptedCandidates = parseBaiduAppCandidates({
|
|
5582
|
+
candidates: tokenMatched,
|
|
5583
|
+
raw: rawBody
|
|
5558
5584
|
});
|
|
5559
|
-
if (decryptedCandidates.length === 0) {
|
|
5560
|
-
logger3.warn(`decrypt failed for all ${decryptable.length} candidate account(s)`);
|
|
5561
|
-
jsonError(res, "decrypt failed");
|
|
5562
|
-
return true;
|
|
5563
|
-
}
|
|
5564
5585
|
const selected = selectDecryptedTarget({ candidates: decryptedCandidates, logger: logger3 });
|
|
5565
5586
|
const target = selected.target;
|
|
5566
|
-
if (!target.account.configured || !target.account.
|
|
5587
|
+
if (!target.account.configured || !target.account.appKey || !target.account.appSecret) {
|
|
5567
5588
|
logger3.warn(`selected account ${target.account.accountId} not fully configured`);
|
|
5568
5589
|
jsonError(res, "openclaw-baiduapp not configured");
|
|
5569
5590
|
return true;
|
|
5570
5591
|
}
|
|
5571
|
-
|
|
5592
|
+
await processBaiduAppInboundMessage({
|
|
5572
5593
|
target,
|
|
5573
5594
|
msg: selected.msg
|
|
5574
5595
|
});
|
|
5575
|
-
jsonOk(
|
|
5576
|
-
res,
|
|
5577
|
-
buildEncryptedJsonReply({
|
|
5578
|
-
account: target.account,
|
|
5579
|
-
plaintextJson: reply,
|
|
5580
|
-
nonce: msgNonce,
|
|
5581
|
-
timestamp: msgTimestamp
|
|
5582
|
-
})
|
|
5583
|
-
);
|
|
5596
|
+
jsonOk(res, {});
|
|
5584
5597
|
return true;
|
|
5585
5598
|
}
|
|
5586
5599
|
|
|
5587
5600
|
// src/poller.ts
|
|
5588
|
-
var DEFAULT_POLL_INTERVAL_MS =
|
|
5601
|
+
var DEFAULT_POLL_INTERVAL_MS = 3e3;
|
|
5589
5602
|
var DEFAULT_POLL_REQUEST_TIMEOUT_MS = 1e4;
|
|
5590
5603
|
var accountPollers = /* @__PURE__ */ new Map();
|
|
5591
5604
|
function buildPollingTextInboundMessage(content) {
|
|
@@ -5596,21 +5609,36 @@ function buildPollingTextInboundMessage(content) {
|
|
|
5596
5609
|
}
|
|
5597
5610
|
};
|
|
5598
5611
|
}
|
|
5612
|
+
function parseTextAndFilesFromList(list) {
|
|
5613
|
+
const textItem = list.find((entry) => entry.type === "text");
|
|
5614
|
+
const fileItems = list.filter((entry) => entry.type === "file");
|
|
5615
|
+
const content = textItem?.type === "text" ? textItem.data.text.content : void 0;
|
|
5616
|
+
const files = fileItems.map((file) => {
|
|
5617
|
+
const fileId = file.data.file_id;
|
|
5618
|
+
return typeof fileId === "string" && fileId.trim() ? { url: fileId, fileType: "file" } : null;
|
|
5619
|
+
}).filter((file) => file != null);
|
|
5620
|
+
return { content, files };
|
|
5621
|
+
}
|
|
5599
5622
|
async function dispatchPendingPollingMessages(data, target) {
|
|
5623
|
+
console.log(data);
|
|
5600
5624
|
if (!target || data.length === 0) {
|
|
5601
5625
|
return;
|
|
5602
5626
|
}
|
|
5603
5627
|
for (const item of data) {
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
}
|
|
5607
|
-
|
|
5608
|
-
if (typeof content !== "string" || content.length === 0) {
|
|
5628
|
+
const list = Array.isArray(item.list) ? item.list : [];
|
|
5629
|
+
const { content, files } = parseTextAndFilesFromList(list);
|
|
5630
|
+
console.log({ content, files });
|
|
5631
|
+
if (typeof content !== "string" && files.length === 0) {
|
|
5609
5632
|
continue;
|
|
5610
5633
|
}
|
|
5611
5634
|
await processBaiduAppInboundMessage({
|
|
5612
5635
|
target,
|
|
5613
|
-
msg:
|
|
5636
|
+
msg: {
|
|
5637
|
+
...buildPollingTextInboundMessage(typeof content === "string" ? content : ""),
|
|
5638
|
+
msgid: typeof item.msgId === "string" ? item.msgId : void 0,
|
|
5639
|
+
agentid: typeof item.agentId === "string" ? item.agentId : void 0,
|
|
5640
|
+
...files.length > 0 ? { files } : {}
|
|
5641
|
+
}
|
|
5614
5642
|
});
|
|
5615
5643
|
}
|
|
5616
5644
|
}
|
|
@@ -5665,12 +5693,29 @@ function createAbortSignalController(params) {
|
|
|
5665
5693
|
};
|
|
5666
5694
|
}
|
|
5667
5695
|
async function pollBaiduAppChatlistOnce(account, loggerOptions, requestOptions) {
|
|
5668
|
-
const endpoint = `${account.apiBase}/
|
|
5696
|
+
const endpoint = `${account.apiBase}/channel/msg/poll`;
|
|
5697
|
+
const logger3 = createLogger("openclaw-baiduapp:poller", loggerOptions);
|
|
5698
|
+
const timestamp = String(Math.floor(Date.now() / 1e3));
|
|
5699
|
+
const nonce = generateNonce();
|
|
5700
|
+
const authorization = buildAuthorizationHeader({
|
|
5701
|
+
ak: account.appKey ?? "",
|
|
5702
|
+
sk: account.appSecret ?? "",
|
|
5703
|
+
timestamp,
|
|
5704
|
+
nonce
|
|
5705
|
+
});
|
|
5669
5706
|
const query = new URLSearchParams({
|
|
5670
5707
|
ak: account.appKey ?? "",
|
|
5671
|
-
|
|
5708
|
+
timestamp,
|
|
5709
|
+
nonce
|
|
5672
5710
|
});
|
|
5673
5711
|
const url = `${endpoint}?${query.toString()}`;
|
|
5712
|
+
const payload = {
|
|
5713
|
+
sessionId: "agent:main:main",
|
|
5714
|
+
num: 5,
|
|
5715
|
+
version: PLUGIN_VERSION
|
|
5716
|
+
};
|
|
5717
|
+
const body = JSON.stringify(payload);
|
|
5718
|
+
console.log("start poll");
|
|
5674
5719
|
const requestSignal = createAbortSignalController({
|
|
5675
5720
|
signal: requestOptions?.signal,
|
|
5676
5721
|
timeoutMs: requestOptions?.timeoutMs
|
|
@@ -5678,8 +5723,13 @@ async function pollBaiduAppChatlistOnce(account, loggerOptions, requestOptions)
|
|
|
5678
5723
|
let response;
|
|
5679
5724
|
try {
|
|
5680
5725
|
response = await (requestOptions?.fetchImpl ?? fetch)(url, {
|
|
5681
|
-
method: "
|
|
5682
|
-
|
|
5726
|
+
method: "POST",
|
|
5727
|
+
body,
|
|
5728
|
+
signal: requestSignal.signal,
|
|
5729
|
+
headers: {
|
|
5730
|
+
"Authorization": authorization,
|
|
5731
|
+
"Content-Type": "application/json"
|
|
5732
|
+
}
|
|
5683
5733
|
});
|
|
5684
5734
|
} catch (error) {
|
|
5685
5735
|
requestSignal.cleanup();
|
|
@@ -5732,10 +5782,13 @@ async function pollBaiduAppChatlistOnce(account, loggerOptions, requestOptions)
|
|
|
5732
5782
|
}
|
|
5733
5783
|
});
|
|
5734
5784
|
}
|
|
5735
|
-
|
|
5785
|
+
if (parsed.code !== 0) {
|
|
5786
|
+
logger3.debug(`Baidu poll returned non-zero code=${String(parsed.code)}, message=${parsed.message}`);
|
|
5787
|
+
}
|
|
5788
|
+
const msgList = Array.isArray(parsed.data?.msgList) ? parsed.data.msgList : [];
|
|
5736
5789
|
return buildPollResult({
|
|
5737
5790
|
ok: true,
|
|
5738
|
-
data
|
|
5791
|
+
data: msgList
|
|
5739
5792
|
});
|
|
5740
5793
|
}
|
|
5741
5794
|
function scheduleNextPoll(account, state) {
|
|
@@ -5858,9 +5911,20 @@ function inferBaiduOutboundFileType(params) {
|
|
|
5858
5911
|
function buildOutboundMediaPayload(params) {
|
|
5859
5912
|
const caption = params.caption?.trim();
|
|
5860
5913
|
return {
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5914
|
+
list: [
|
|
5915
|
+
...caption ? [{
|
|
5916
|
+
type: "text",
|
|
5917
|
+
data: {
|
|
5918
|
+
text: { content: caption }
|
|
5919
|
+
}
|
|
5920
|
+
}] : [],
|
|
5921
|
+
{
|
|
5922
|
+
type: "file",
|
|
5923
|
+
data: {
|
|
5924
|
+
file_id: params.uploadedUrl
|
|
5925
|
+
}
|
|
5926
|
+
}
|
|
5927
|
+
]
|
|
5864
5928
|
};
|
|
5865
5929
|
}
|
|
5866
5930
|
function resolveDirectOutboundFiles(files) {
|
|
@@ -6097,7 +6161,10 @@ var baiduAppPlugin = {
|
|
|
6097
6161
|
};
|
|
6098
6162
|
}
|
|
6099
6163
|
try {
|
|
6100
|
-
const result = await sendBaiduAppMessage(account, params.text
|
|
6164
|
+
const result = await sendBaiduAppMessage(account, params.text, {
|
|
6165
|
+
agentid: account.accountId,
|
|
6166
|
+
isActive: true
|
|
6167
|
+
});
|
|
6101
6168
|
return {
|
|
6102
6169
|
channel: "openclaw-baiduapp",
|
|
6103
6170
|
ok: result.ok,
|
|
@@ -6142,7 +6209,8 @@ var baiduAppPlugin = {
|
|
|
6142
6209
|
caption: params.text,
|
|
6143
6210
|
uploadedUrl: remoteUrl,
|
|
6144
6211
|
fileType: inferBaiduOutboundFileType({ mediaPath: remoteUrl })
|
|
6145
|
-
})
|
|
6212
|
+
}),
|
|
6213
|
+
{ agentid: account.accountId, isActive: true }
|
|
6146
6214
|
);
|
|
6147
6215
|
return {
|
|
6148
6216
|
channel: "openclaw-baiduapp",
|
|
@@ -6184,7 +6252,8 @@ var baiduAppPlugin = {
|
|
|
6184
6252
|
fileType: inferBaiduOutboundFileType({
|
|
6185
6253
|
mediaPath: uploaded.fileName || localMediaPath
|
|
6186
6254
|
})
|
|
6187
|
-
})
|
|
6255
|
+
}),
|
|
6256
|
+
{ agentid: account.accountId, isActive: true }
|
|
6188
6257
|
);
|
|
6189
6258
|
return {
|
|
6190
6259
|
channel: "openclaw-baiduapp",
|
|
@@ -6206,6 +6275,18 @@ var baiduAppPlugin = {
|
|
|
6206
6275
|
}
|
|
6207
6276
|
}
|
|
6208
6277
|
},
|
|
6278
|
+
auth: {
|
|
6279
|
+
login: async (params) => {
|
|
6280
|
+
void params.channelInput;
|
|
6281
|
+
const { loginBaiduApp: loginBaiduApp2 } = await Promise.resolve().then(() => (init_login(), login_exports));
|
|
6282
|
+
await loginBaiduApp2({
|
|
6283
|
+
cfg: params.cfg,
|
|
6284
|
+
accountId: params.accountId,
|
|
6285
|
+
runtime: params.runtime,
|
|
6286
|
+
verbose: params.verbose
|
|
6287
|
+
});
|
|
6288
|
+
}
|
|
6289
|
+
},
|
|
6209
6290
|
gateway: {
|
|
6210
6291
|
startAccount: async (ctx) => {
|
|
6211
6292
|
ctx.setStatus?.({ accountId: ctx.accountId });
|
|
@@ -6243,21 +6324,19 @@ var baiduAppPlugin = {
|
|
|
6243
6324
|
existing();
|
|
6244
6325
|
}
|
|
6245
6326
|
unregisterHooks.set(ctx.accountId, unregister);
|
|
6246
|
-
|
|
6247
|
-
|
|
6327
|
+
startAccountPolling({
|
|
6328
|
+
account,
|
|
6329
|
+
dispatchTarget: {
|
|
6248
6330
|
account,
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
}
|
|
6259
|
-
});
|
|
6260
|
-
}
|
|
6331
|
+
config: ctx.cfg ?? {},
|
|
6332
|
+
runtime: runtime2,
|
|
6333
|
+
statusSink: (patch) => ctx.setStatus?.({ accountId: ctx.accountId, ...patch })
|
|
6334
|
+
},
|
|
6335
|
+
onError: (error) => {
|
|
6336
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6337
|
+
ctx.log?.error(`[openclaw-baiduapp] polling failed for account ${ctx.accountId}: ${message}`);
|
|
6338
|
+
}
|
|
6339
|
+
});
|
|
6261
6340
|
ctx.log?.info(
|
|
6262
6341
|
`[openclaw-baiduapp] webhook registered at ${path4} for account ${ctx.accountId} (canSendActive=${account.canSendActive})`
|
|
6263
6342
|
);
|
|
@@ -6309,7 +6388,7 @@ async function sendMessage(account, options) {
|
|
|
6309
6388
|
};
|
|
6310
6389
|
}
|
|
6311
6390
|
try {
|
|
6312
|
-
const textResult = await sendBaiduAppMessage(account, options.text);
|
|
6391
|
+
const textResult = await sendBaiduAppMessage(account, options.text, { isActive: true });
|
|
6313
6392
|
return {
|
|
6314
6393
|
ok: textResult.ok,
|
|
6315
6394
|
msgid: textResult.msgid,
|