@searchfe/openclaw-baiduapp 0.1.9-beta.3 → 0.1.9

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/index.js CHANGED
@@ -1,8 +1,6 @@
1
- import { spawnSync } from 'child_process';
2
- import readline from 'readline';
3
1
  import path2 from 'path';
4
2
  import { fileURLToPath } from 'url';
5
- import crypto from 'crypto';
3
+ import crypto3 from 'crypto';
6
4
  import { createRequire } from 'module';
7
5
  import { lookup } from 'dns/promises';
8
6
  import fs2 from 'fs/promises';
@@ -1360,19 +1358,19 @@ var require_package = __commonJS({
1360
1358
  var require_crypto = __commonJS({
1361
1359
  "node_modules/.pnpm/@baiducloud+sdk@1.0.7/node_modules/@baiducloud/sdk/src/crypto.js"(exports$1) {
1362
1360
  var fs3 = __require("fs");
1363
- var crypto3 = __require("crypto");
1361
+ var crypto4 = __require("crypto");
1364
1362
  var Q = require_q();
1365
1363
  exports$1.md5sum = function(data, enc, digest) {
1366
1364
  if (!Buffer.isBuffer(data)) {
1367
1365
  data = new Buffer(data, enc || "UTF-8");
1368
1366
  }
1369
- var md5 = crypto3.createHash("md5");
1367
+ var md5 = crypto4.createHash("md5");
1370
1368
  md5.update(data);
1371
1369
  return md5.digest(digest || "base64");
1372
1370
  };
1373
1371
  exports$1.md5stream = function(stream, digest) {
1374
1372
  var deferred = Q.defer();
1375
- var md5 = crypto3.createHash("md5");
1373
+ var md5 = crypto4.createHash("md5");
1376
1374
  stream.on("data", function(chunk2) {
1377
1375
  md5.update(chunk2);
1378
1376
  });
@@ -5131,8 +5129,8 @@ var require_auth = __commonJS({
5131
5129
  return [canonicalHeaders.join("\n"), signedHeaders];
5132
5130
  };
5133
5131
  Auth.prototype.hash = function(data, key) {
5134
- var crypto3 = __require("crypto");
5135
- var sha256Hmac = crypto3.createHmac("sha256", key);
5132
+ var crypto4 = __require("crypto");
5133
+ var sha256Hmac = crypto4.createHmac("sha256", key);
5136
5134
  sha256Hmac.update(data);
5137
5135
  return sha256Hmac.digest("hex");
5138
5136
  };
@@ -14399,7 +14397,7 @@ var require_bos_client = __commonJS({
14399
14397
  var H = require_headers();
14400
14398
  var strings = require_strings();
14401
14399
  var Auth = require_auth();
14402
- var crypto3 = require_crypto();
14400
+ var crypto4 = require_crypto();
14403
14401
  var HttpClient = require_http_client();
14404
14402
  var BceBaseClient = require_bce_base_client();
14405
14403
  var MimeType = require_mime_types();
@@ -15016,7 +15014,7 @@ var require_bos_client = __commonJS({
15016
15014
  var headers = {};
15017
15015
  headers[H.CONTENT_LENGTH] = Buffer.byteLength(data);
15018
15016
  headers[H.CONTENT_TYPE] = options[H.CONTENT_TYPE] || MimeType.guess(path4.extname(key));
15019
- headers[H.CONTENT_MD5] = crypto3.md5sum(data);
15017
+ headers[H.CONTENT_MD5] = crypto4.md5sum(data);
15020
15018
  options = u.extend(headers, options);
15021
15019
  return this.putObject(bucketName, key, data, options);
15022
15020
  };
@@ -15048,7 +15046,7 @@ var require_bos_client = __commonJS({
15048
15046
  }
15049
15047
  if (!u.has(options, H.CONTENT_MD5)) {
15050
15048
  var fp2 = fs3.createReadStream(filename, streamOptions);
15051
- return crypto3.md5stream(fp2).then(function(md5sum) {
15049
+ return crypto4.md5stream(fp2).then(function(md5sum) {
15052
15050
  options[H.CONTENT_MD5] = md5sum;
15053
15051
  return putObjectWithRetry(options.retryCount || MAX_RETRY_COUNT);
15054
15052
  });
@@ -15383,7 +15381,7 @@ var require_bos_client = __commonJS({
15383
15381
  var headers = {};
15384
15382
  headers[H.CONTENT_LENGTH] = Buffer.byteLength(data);
15385
15383
  headers[H.CONTENT_TYPE] = options[H.CONTENT_TYPE] || MimeType.guess(path4.extname(key));
15386
- headers[H.CONTENT_MD5] = crypto3.md5sum(data);
15384
+ headers[H.CONTENT_MD5] = crypto4.md5sum(data);
15387
15385
  options = u.extend(headers, options);
15388
15386
  return this.appendObject(bucketName, key, data, offset, options);
15389
15387
  };
@@ -15408,7 +15406,7 @@ var require_bos_client = __commonJS({
15408
15406
  if (!u.has(options, H.CONTENT_MD5)) {
15409
15407
  var me = this;
15410
15408
  var fp2 = fs3.createReadStream(filename, streamOptions);
15411
- return crypto3.md5stream(fp2).then(function(md5sum) {
15409
+ return crypto4.md5stream(fp2).then(function(md5sum) {
15412
15410
  options[H.CONTENT_MD5] = md5sum;
15413
15411
  return me.appendObject(bucketName, key, fp, offset, options);
15414
15412
  });
@@ -15989,7 +15987,7 @@ var require_bos_client = __commonJS({
15989
15987
  // node_modules/.pnpm/@baiducloud+sdk@1.0.7/node_modules/@baiducloud/sdk/src/bcs_client.js
15990
15988
  var require_bcs_client = __commonJS({
15991
15989
  "node_modules/.pnpm/@baiducloud+sdk@1.0.7/node_modules/@baiducloud/sdk/src/bcs_client.js"(exports$1, module) {
15992
- var crypto3 = __require("crypto");
15990
+ var crypto4 = __require("crypto");
15993
15991
  var util2 = __require("util");
15994
15992
  var path4 = __require("path");
15995
15993
  var fs3 = __require("fs");
@@ -16128,7 +16126,7 @@ var require_bcs_client = __commonJS({
16128
16126
  "Object=" + objectName
16129
16127
  ].join("\n");
16130
16128
  var content = flag + "\n" + body + "\n";
16131
- var hmac = crypto3.createHmac("sha1", credentials.sk);
16129
+ var hmac = crypto4.createHmac("sha1", credentials.sk);
16132
16130
  hmac.update(new Buffer(content, "utf-8"));
16133
16131
  var digest = encodeURIComponent(hmac.digest("base64")).replace(/%2F/g, "/");
16134
16132
  return [flag, credentials.ak, digest].join(":");
@@ -17969,7 +17967,7 @@ var require_doc_client = __commonJS({
17969
17967
  var BosClient = require_bos_client();
17970
17968
  var BceBaseClient = require_bce_base_client();
17971
17969
  var UploadHelper = require_helper();
17972
- var crypto3 = require_crypto();
17970
+ var crypto4 = require_crypto();
17973
17971
  var DATA_TYPE_FILE = 1;
17974
17972
  var DATA_TYPE_BUFFER = 2;
17975
17973
  var DATA_TYPE_BLOB = 4;
@@ -18041,12 +18039,12 @@ var require_doc_client = __commonJS({
18041
18039
  }
18042
18040
  var self2 = this;
18043
18041
  if (dataType === DATA_TYPE_FILE) {
18044
- return crypto3.md5stream(fs3.createReadStream(data), "hex").then(function(md5) {
18042
+ return crypto4.md5stream(fs3.createReadStream(data), "hex").then(function(md5) {
18045
18043
  options.meta.md5 = md5;
18046
18044
  return self2._doCreate(data, options);
18047
18045
  });
18048
18046
  } else if (dataType === DATA_TYPE_BLOB) {
18049
- return crypto3.md5blob(data, "hex").then(function(md5) {
18047
+ return crypto4.md5blob(data, "hex").then(function(md5) {
18050
18048
  options.meta.md5 = md5;
18051
18049
  return self2._doCreate(data, options);
18052
18050
  });
@@ -22789,111 +22787,6 @@ var require_sdk = __commonJS({
22789
22787
  }
22790
22788
  });
22791
22789
 
22792
- // src/auth/login.ts
22793
- var login_exports = {};
22794
- __export(login_exports, {
22795
- loginBaiduApp: () => loginBaiduApp
22796
- });
22797
- function createTerminalPrompter() {
22798
- const rl = readline.createInterface({
22799
- input: process.stdin,
22800
- output: process.stdout
22801
- });
22802
- const question = (message) => new Promise((resolve) => {
22803
- rl.question(message, (answer) => resolve(answer));
22804
- });
22805
- return {
22806
- select: async (message, choices) => {
22807
- while (true) {
22808
- process.stdout.write(`${message}
22809
- `);
22810
- for (const [index2, choice] of choices.entries()) {
22811
- process.stdout.write(`${index2 + 1}. ${choice}
22812
- `);
22813
- }
22814
- const answer = (await question("\u8BF7\u9009\u62E9\u5E8F\u53F7: ")).trim();
22815
- const choiceIndex = Number(answer);
22816
- if (Number.isInteger(choiceIndex) && choiceIndex >= 1 && choiceIndex <= choices.length) {
22817
- return choices[choiceIndex - 1];
22818
- }
22819
- process.stdout.write(`\u8BF7\u8F93\u5165 1-${choices.length} \u4E4B\u95F4\u7684\u5E8F\u53F7\u3002
22820
- `);
22821
- }
22822
- },
22823
- text: async (message, opts) => {
22824
- while (true) {
22825
- const answer = (await question(`${message}: `)).trim();
22826
- if (!opts?.required || answer) {
22827
- return answer;
22828
- }
22829
- process.stdout.write("\u8BE5\u9879\u4E3A\u5FC5\u586B\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165\u3002\n");
22830
- }
22831
- },
22832
- close: () => {
22833
- rl.close();
22834
- }
22835
- };
22836
- }
22837
- function redactValue(value, opts) {
22838
- if (!value) {
22839
- return "(empty)";
22840
- }
22841
- const keepStart = opts?.keepStart ?? 2;
22842
- const keepEnd = opts?.keepEnd ?? 2;
22843
- if (value.length <= keepStart + keepEnd) {
22844
- return "*".repeat(value.length);
22845
- }
22846
- return `${value.slice(0, keepStart)}***${value.slice(-keepEnd)}`;
22847
- }
22848
- function setConfigValue(key, value) {
22849
- const args = ["config", "set", key, String(value)];
22850
- const result2 = spawnSync("openclaw", args, {
22851
- stdio: ["ignore", "pipe", "pipe"],
22852
- encoding: "utf8",
22853
- timeout: 15e3
22854
- });
22855
- if (result2.status !== 0) {
22856
- const stderr = (result2.stderr ?? "").trim();
22857
- throw new Error(`openclaw config set failed: ${stderr || `exit code ${result2.status}`}`);
22858
- }
22859
- }
22860
- async function loginBaiduApp(params) {
22861
- void params.cfg;
22862
- void params.verbose;
22863
- const agentId = params.accountId?.trim() || "main";
22864
- const prompter = createTerminalPrompter();
22865
- try {
22866
- const mode = await prompter.select("\u8BF7\u9009\u62E9\u767E\u5EA6 App \u914D\u7F6E\u65B9\u5F0F", [
22867
- "\u624B\u52A8\u586B\u5199",
22868
- "\u626B\u7801\u914D\u7F6E\uFF08\u5373\u5C06\u652F\u6301\uFF09"
22869
- ]);
22870
- if (mode === "\u626B\u7801\u914D\u7F6E\uFF08\u5373\u5C06\u652F\u6301\uFF09") {
22871
- params.runtime.log("\u23F3 \u626B\u7801\u914D\u7F6E\u529F\u80FD\u6B63\u5728\u5F00\u53D1\u4E2D\uFF0C\u656C\u8BF7\u671F\u5F85...");
22872
- params.runtime.log("\u8BF7\u5148\u4F7F\u7528\u624B\u52A8\u586B\u5199\u65B9\u5F0F\u5B8C\u6210\u914D\u7F6E\u3002");
22873
- return;
22874
- }
22875
- const appKey = await prompter.text("App Key", { required: true });
22876
- const appSecret = await prompter.text("App Secret", { required: true });
22877
- const accountKeyPrefix = `channels.openclaw-baiduapp.accounts.${agentId}`;
22878
- setConfigValue(`${accountKeyPrefix}.appKey`, appKey);
22879
- setConfigValue(`${accountKeyPrefix}.appSecret`, appSecret);
22880
- setConfigValue(`${accountKeyPrefix}.enabled`, true);
22881
- params.runtime.log(`\u2705 openclaw-baiduapp \u5DF2\u5B8C\u6210\u914D\u7F6E\uFF08account: ${agentId}\uFF09`);
22882
- params.runtime.log(`- appKey: ${redactValue(appKey, { keepStart: 3, keepEnd: 3 })}`);
22883
- params.runtime.log(`- appSecret: ${redactValue(appSecret, { keepStart: 3, keepEnd: 3 })}`);
22884
- } catch (error) {
22885
- const message = error instanceof Error ? error.message : String(error);
22886
- params.runtime.error(`openclaw-baiduapp \u767B\u5F55\u914D\u7F6E\u5931\u8D25\uFF1A${message}`);
22887
- throw error;
22888
- } finally {
22889
- prompter.close();
22890
- }
22891
- }
22892
- var init_login = __esm({
22893
- "src/auth/login.ts"() {
22894
- }
22895
- });
22896
-
22897
22790
  // node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
22898
22791
  var external_exports = {};
22899
22792
  __export(external_exports, {
@@ -26936,13 +26829,14 @@ var NEVER = INVALID;
26936
26829
 
26937
26830
  // src/config.ts
26938
26831
  var DEFAULT_ACCOUNT_ID = "default";
26939
- var DEFAULT_AGENT_ID = "main";
26940
26832
  var DEFAULT_API_BASE = "https://claw.baidu.com";
26941
26833
  var BaiduAppAccountSchema = external_exports.object({
26942
26834
  name: external_exports.string().optional(),
26943
26835
  enabled: external_exports.boolean().optional(),
26944
26836
  pollingEnabled: external_exports.boolean().optional(),
26945
26837
  webhookPath: external_exports.string().optional(),
26838
+ token: external_exports.string().optional(),
26839
+ encodingAESKey: external_exports.string().optional(),
26946
26840
  appKey: external_exports.string().optional(),
26947
26841
  appSecret: external_exports.string().optional(),
26948
26842
  apiBase: external_exports.string().optional(),
@@ -26961,6 +26855,8 @@ var BaiduAppConfigJsonSchema = {
26961
26855
  enabled: { type: "boolean" },
26962
26856
  pollingEnabled: { type: "boolean" },
26963
26857
  webhookPath: { type: "string" },
26858
+ token: { type: "string" },
26859
+ encodingAESKey: { type: "string" },
26964
26860
  appKey: { type: "string" },
26965
26861
  appSecret: { type: "string" },
26966
26862
  apiBase: { type: "string" },
@@ -26976,6 +26872,8 @@ var BaiduAppConfigJsonSchema = {
26976
26872
  enabled: { type: "boolean" },
26977
26873
  pollingEnabled: { type: "boolean" },
26978
26874
  webhookPath: { type: "string" },
26875
+ token: { type: "string" },
26876
+ encodingAESKey: { type: "string" },
26979
26877
  appKey: { type: "string" },
26980
26878
  appSecret: { type: "string" },
26981
26879
  apiBase: { type: "string" },
@@ -26990,10 +26888,6 @@ function normalizeAccountId(raw) {
26990
26888
  const trimmed = String(raw ?? "").trim();
26991
26889
  return trimmed || DEFAULT_ACCOUNT_ID;
26992
26890
  }
26993
- function extractAgentId(msg) {
26994
- const raw = msg.agentid ?? "";
26995
- return raw.trim() || DEFAULT_AGENT_ID;
26996
- }
26997
26891
  function listConfiguredAccountIds(cfg) {
26998
26892
  const accounts = cfg.channels?.["openclaw-baiduapp"]?.accounts;
26999
26893
  if (!accounts || typeof accounts !== "object") {
@@ -27041,10 +26935,12 @@ function resolveBaiduAppAccount(params) {
27041
26935
  const merged = mergeBaiduAppAccountConfig(params.cfg, accountId);
27042
26936
  const enabled = baseEnabled && merged.enabled !== false;
27043
26937
  const isDefaultAccount = accountId === DEFAULT_ACCOUNT_ID;
26938
+ const token = merged.token?.trim() || (isDefaultAccount ? process.env.BAIDU_APP_TOKEN?.trim() : void 0) || void 0;
26939
+ const encodingAESKey = merged.encodingAESKey?.trim() || (isDefaultAccount ? process.env.BAIDU_APP_ENCODING_AES_KEY?.trim() : void 0) || void 0;
27044
26940
  const appKey = merged.appKey?.trim() || (isDefaultAccount ? process.env.BAIDU_APP_KEY?.trim() : void 0) || void 0;
27045
26941
  const appSecret = merged.appSecret?.trim() || (isDefaultAccount ? process.env.BAIDU_APP_SECRET?.trim() : void 0) || void 0;
27046
- const configured = Boolean(appKey && appSecret);
27047
- const canSendActive = Boolean(appKey && appSecret);
26942
+ const configured = Boolean(token && encodingAESKey);
26943
+ const canSendActive = Boolean(appKey && appSecret && token && encodingAESKey);
27048
26944
  const rawApiBase = merged.apiBase?.trim() || (isDefaultAccount ? process.env.BAIDU_API_BASE?.trim() : void 0) || void 0;
27049
26945
  const apiBase = (rawApiBase || DEFAULT_API_BASE).replace(/\/+$/, "");
27050
26946
  return {
@@ -27052,6 +26948,8 @@ function resolveBaiduAppAccount(params) {
27052
26948
  name: merged.name?.trim() || void 0,
27053
26949
  enabled,
27054
26950
  configured,
26951
+ token,
26952
+ encodingAESKey,
27055
26953
  appKey,
27056
26954
  appSecret,
27057
26955
  apiBase,
@@ -27059,37 +26957,6 @@ function resolveBaiduAppAccount(params) {
27059
26957
  config: merged
27060
26958
  };
27061
26959
  }
27062
- function resolveAgentField(agentCfg, mainCfg, baseAccount, field) {
27063
- return agentCfg?.[field]?.trim() || mainCfg?.[field]?.trim() || baseAccount[field];
27064
- }
27065
- function resolveAgentAccount(params) {
27066
- const { baseAccount, cfg, agentId } = params;
27067
- if (agentId === baseAccount.accountId) {
27068
- return baseAccount;
27069
- }
27070
- const accounts = cfg.channels?.["openclaw-baiduapp"]?.accounts;
27071
- const agentCfg = accounts?.[agentId] && typeof accounts[agentId] === "object" ? accounts[agentId] : void 0;
27072
- const mainCfg = agentId !== DEFAULT_AGENT_ID && accounts?.[DEFAULT_AGENT_ID] && typeof accounts[DEFAULT_AGENT_ID] === "object" ? accounts[DEFAULT_AGENT_ID] : void 0;
27073
- const appKey = resolveAgentField(agentCfg, mainCfg, baseAccount, "appKey");
27074
- const appSecret = resolveAgentField(agentCfg, mainCfg, baseAccount, "appSecret");
27075
- const apiBase = baseAccount.apiBase;
27076
- const name = resolveAgentField(agentCfg, mainCfg, baseAccount, "name");
27077
- const configured = Boolean(appKey && appSecret);
27078
- const canSendActive = Boolean(appKey && appSecret);
27079
- const agentEnabled = agentCfg?.enabled !== false;
27080
- return {
27081
- ...baseAccount,
27082
- accountId: agentId,
27083
- name: name || baseAccount.name,
27084
- enabled: agentEnabled && baseAccount.enabled,
27085
- configured,
27086
- appKey,
27087
- appSecret,
27088
- apiBase,
27089
- canSendActive,
27090
- config: { ...baseAccount.config, ...mainCfg ?? {}, ...agentCfg ?? {} }
27091
- };
27092
- }
27093
26960
 
27094
26961
  // src/shared/logger.ts
27095
26962
  function createLogger(prefix, opts) {
@@ -27102,85 +26969,135 @@ function createLogger(prefix, opts) {
27102
26969
  error: (msg) => errorFn(`[${prefix}] [ERROR] ${msg}`)
27103
26970
  };
27104
26971
  }
26972
+ function decodeEncodingAESKey(encodingAESKey) {
26973
+ const trimmed = encodingAESKey.trim();
26974
+ if (!trimmed) {
26975
+ throw new Error("encodingAESKey missing");
26976
+ }
26977
+ const withPadding = trimmed.endsWith("=") ? trimmed : `${trimmed}=`;
26978
+ const key = Buffer.from(withPadding, "base64");
26979
+ if (key.length !== 32) {
26980
+ throw new Error(`invalid encodingAESKey (expected 32 bytes after base64 decode, got ${key.length})`);
26981
+ }
26982
+ return key;
26983
+ }
26984
+ var PKCS7_BLOCK_SIZE = 32;
26985
+ function pkcs7Pad(buf, blockSize) {
26986
+ const mod = buf.length % blockSize;
26987
+ const pad = mod === 0 ? blockSize : blockSize - mod;
26988
+ return Buffer.concat([buf, Buffer.alloc(pad, pad)]);
26989
+ }
26990
+ function pkcs7Unpad(buf, blockSize) {
26991
+ if (buf.length === 0) {
26992
+ throw new Error("invalid pkcs7 payload");
26993
+ }
26994
+ const pad = buf[buf.length - 1];
26995
+ if (!pad || pad < 1 || pad > blockSize || pad > buf.length) {
26996
+ throw new Error("invalid pkcs7 padding");
26997
+ }
26998
+ for (let i = 1; i <= pad; i += 1) {
26999
+ if (buf[buf.length - i] !== pad) {
27000
+ throw new Error("invalid pkcs7 padding");
27001
+ }
27002
+ }
27003
+ return buf.subarray(0, buf.length - pad);
27004
+ }
27105
27005
  function sha1Hex(input) {
27106
- return crypto.createHash("sha1").update(input).digest("hex");
27006
+ return crypto3.createHash("sha1").update(input).digest("hex");
27107
27007
  }
27108
- function computeAKSKBearerToken(params) {
27109
- return sha1Hex(params.ak + params.sk + params.timestamp + params.nonce);
27008
+ function computeBaiduAppMsgSignature(params) {
27009
+ const parts = [params.token, params.timestamp, params.nonce, params.encrypt].map((value) => String(value ?? "")).sort();
27010
+ return sha1Hex(parts.join(""));
27110
27011
  }
27111
- function verifyAKSKBearerToken(params) {
27112
- const expected = computeAKSKBearerToken({
27113
- ak: params.ak,
27114
- sk: params.sk,
27012
+ function verifyBaiduAppSignature(params) {
27013
+ const expected = computeBaiduAppMsgSignature({
27014
+ token: params.token,
27115
27015
  timestamp: params.timestamp,
27116
- nonce: params.nonce
27016
+ nonce: params.nonce,
27017
+ encrypt: params.encrypt
27117
27018
  });
27118
- return expected === params.token;
27119
- }
27120
- function generateNonce() {
27121
- return crypto.randomBytes(8).toString("hex");
27019
+ return expected === params.signature;
27020
+ }
27021
+ function decryptBaiduAppEncrypted(params) {
27022
+ const aesKey = decodeEncodingAESKey(params.encodingAESKey);
27023
+ const iv = aesKey.subarray(0, 16);
27024
+ const decipher = crypto3.createDecipheriv("aes-256-cbc", aesKey, iv);
27025
+ decipher.setAutoPadding(false);
27026
+ const decryptedPadded = Buffer.concat([decipher.update(Buffer.from(params.encrypt, "base64")), decipher.final()]);
27027
+ const decrypted = pkcs7Unpad(decryptedPadded, PKCS7_BLOCK_SIZE);
27028
+ if (decrypted.length < 20) {
27029
+ throw new Error(`invalid decrypted payload (expected at least 20 bytes, got ${decrypted.length})`);
27030
+ }
27031
+ const msgLen = decrypted.readUInt32BE(16);
27032
+ const msgStart = 20;
27033
+ const msgEnd = msgStart + msgLen;
27034
+ if (msgEnd > decrypted.length) {
27035
+ throw new Error(`invalid decrypted msg length (msgEnd=${msgEnd}, payloadLength=${decrypted.length})`);
27036
+ }
27037
+ return decrypted.subarray(msgStart, msgEnd).toString("utf8");
27038
+ }
27039
+ function encryptBaiduAppPlaintext(params) {
27040
+ const aesKey = decodeEncodingAESKey(params.encodingAESKey);
27041
+ const iv = aesKey.subarray(0, 16);
27042
+ const random16 = crypto3.randomBytes(16);
27043
+ const msg = Buffer.from(params.plaintext ?? "", "utf8");
27044
+ const msgLen = Buffer.alloc(4);
27045
+ msgLen.writeUInt32BE(msg.length, 0);
27046
+ const raw = Buffer.concat([random16, msgLen, msg]);
27047
+ const padded = pkcs7Pad(raw, PKCS7_BLOCK_SIZE);
27048
+ const cipher = crypto3.createCipheriv("aes-256-cbc", aesKey, iv);
27049
+ cipher.setAutoPadding(false);
27050
+ const encrypted = Buffer.concat([cipher.update(padded), cipher.final()]);
27051
+ return encrypted.toString("base64");
27122
27052
  }
27123
- function buildAuthorizationHeader(params) {
27124
- const token = computeAKSKBearerToken(params);
27125
- return `Bearer ${token}`;
27126
- }
27127
-
27128
- // src/types.ts
27129
- var DEFAULT_BAIDU_APP_SESSION_ID = "agent:main:main";
27130
27053
  var require2 = createRequire(import.meta.url);
27131
27054
  var pkg = require2("../package.json");
27132
27055
  var PLUGIN_VERSION = pkg.version;
27133
27056
 
27134
27057
  // src/api.ts
27135
27058
  var logger = createLogger("openclaw-baiduapp");
27136
- var DEFAULT_sessionId = DEFAULT_BAIDU_APP_SESSION_ID;
27137
27059
  async function sendBaiduAppMessage(account, message, options) {
27138
27060
  if (!account.canSendActive) {
27139
- logger.error("Account not configured for active sending (missing appKey or appSecret)");
27061
+ logger.error("Account not configured for active sending (missing appKey, token, or encodingAESKey)");
27140
27062
  return {
27141
27063
  ok: false,
27142
27064
  errcode: -1,
27143
- errmsg: "Account not configured for active sending (missing appKey or appSecret)"
27065
+ errmsg: "Account not configured for active sending (missing appKey, token, or encodingAESKey)"
27144
27066
  };
27145
27067
  }
27146
27068
  const normalizedPayload = typeof message === "string" ? {
27147
- list: [{
27148
- type: "text",
27149
- data: {
27150
- text: { content: message }
27151
- }
27152
- }]
27069
+ msgtype: "text",
27070
+ text: { content: message }
27153
27071
  } : message;
27154
- const sessionId = options?.sessionId ?? DEFAULT_sessionId;
27155
- const callbackBody = {
27156
- sessionId,
27157
- list: normalizedPayload.list,
27072
+ const payload = {
27073
+ ...normalizedPayload,
27158
27074
  version: PLUGIN_VERSION,
27159
- isActive: options?.isActive || false,
27160
- ...options?.agentid ? { agentid: options.agentid } : {},
27161
- ...options?.chunkKey != null ? { chunkKey: options.chunkKey } : {},
27162
- ...options?.replyToMsgId ? { replyToMsgId: options.replyToMsgId } : {}
27075
+ ...options?.msgid != null ? { msgid: options.msgid } : {},
27076
+ ...options?.streamId != null ? { streamId: options.streamId } : {},
27077
+ ...options?.chunkKey != null ? { chunkKey: options.chunkKey } : {}
27163
27078
  };
27079
+ const plaintext = JSON.stringify(payload);
27080
+ const encrypt = encryptBaiduAppPlaintext({
27081
+ encodingAESKey: account.encodingAESKey ?? "",
27082
+ plaintext
27083
+ });
27164
27084
  const timestamp = String(Math.floor(Date.now() / 1e3));
27165
- const nonce = generateNonce();
27166
- const authorization = buildAuthorizationHeader({
27167
- ak: account.appKey ?? "",
27168
- sk: account.appSecret ?? "",
27085
+ const nonce = crypto3.randomBytes(8).toString("hex");
27086
+ const msgSignature = computeBaiduAppMsgSignature({
27087
+ token: account.token ?? "",
27169
27088
  timestamp,
27170
- nonce
27089
+ nonce,
27090
+ encrypt
27171
27091
  });
27172
- const sendMessageUrl = `${account.apiBase}/channel/msg/callback`;
27173
- const url = `${sendMessageUrl}?timestamp=${encodeURIComponent(timestamp)}&ak=${encodeURIComponent(account.appKey ?? "")}&nonce=${encodeURIComponent(nonce)}`;
27174
- const body = JSON.stringify(callbackBody);
27092
+ const sendMessageUrl = `${account.apiBase}/chat/openclaw/callback`;
27093
+ const url = `${sendMessageUrl}?timestamp=${encodeURIComponent(timestamp)}&ak=${encodeURIComponent(account.appKey ?? "")}&nonce=${encodeURIComponent(nonce)}&msg_signature=${encodeURIComponent(msgSignature)}`;
27094
+ const body = JSON.stringify({ encrypt });
27175
27095
  logger.info(`POST ${url}`);
27176
27096
  logger.debug(`request body: ${body}`);
27177
27097
  const resp = await fetch(url, {
27178
27098
  method: "POST",
27179
27099
  body,
27180
- headers: {
27181
- "Authorization": authorization,
27182
- "Content-Type": "application/json"
27183
- }
27100
+ headers: { "Content-Type": "application/json" }
27184
27101
  });
27185
27102
  const text = await resp.text();
27186
27103
  if (!text) {
@@ -27196,15 +27113,6 @@ async function sendBaiduAppMessage(account, message, options) {
27196
27113
  logger.error(`request failed: ${errmsg}`);
27197
27114
  return { ok: false, errcode: resp.status, errmsg };
27198
27115
  }
27199
- if (data.code !== 0) {
27200
- const errmsg = data.msg ?? `channel callback failed with code ${String(data.code)}`;
27201
- logger.error(`request failed: ${errmsg}`);
27202
- return {
27203
- ok: false,
27204
- errcode: data.code,
27205
- errmsg
27206
- };
27207
- }
27208
27116
  const result2 = {
27209
27117
  ok: true
27210
27118
  };
@@ -27230,21 +27138,21 @@ function buildMediaPayload(mediaList, opts) {
27230
27138
 
27231
27139
  // src/bot.ts
27232
27140
  function extractBaiduAppTextContent(msg) {
27233
- const msgtype = String(msg.msgtype ?? "").toLowerCase();
27141
+ const msgtype = String(msg.msgtype ?? msg.MsgType ?? "").toLowerCase();
27234
27142
  if (msgtype === "text") {
27235
- const content = msg.text?.content;
27143
+ const content = msg.text?.content ?? msg.Content;
27236
27144
  return typeof content === "string" ? content : "";
27237
27145
  }
27238
27146
  if (msgtype === "event") {
27239
27147
  const eventtype = String(
27240
- msg.event?.eventtype ?? ""
27148
+ msg.event?.eventtype ?? msg.Event ?? ""
27241
27149
  ).trim();
27242
27150
  return eventtype ? `[event] ${eventtype}` : "[event]";
27243
27151
  }
27244
27152
  return msgtype ? `[${msgtype}]` : "";
27245
27153
  }
27246
27154
  function canDispatchBaiduAppInboundMessage(msg) {
27247
- const msgtype = String(msg.msgtype ?? "").toLowerCase();
27155
+ const msgtype = String(msg.msgtype ?? msg.MsgType ?? "").toLowerCase();
27248
27156
  if (msgtype === "text") {
27249
27157
  if (extractBaiduAppTextContent(msg)) {
27250
27158
  return true;
@@ -27314,7 +27222,7 @@ async function dispatchBaiduAppMessage(params) {
27314
27222
  cfg: safeCfg,
27315
27223
  channel: "openclaw-baiduapp",
27316
27224
  accountId: account.accountId,
27317
- peer: { kind: "dm", id: account.accountId || DEFAULT_AGENT_ID }
27225
+ peer: { kind: "dm", id: "default" }
27318
27226
  });
27319
27227
  logger3.info(`SessionKey: ${route.sessionKey}`);
27320
27228
  logger3.info(
@@ -27344,7 +27252,7 @@ async function dispatchBaiduAppMessage(params) {
27344
27252
  envelope: envelopeOptions,
27345
27253
  body: rawBody
27346
27254
  }) : rawBody;
27347
- const msgid = msg.msgid ?? void 0;
27255
+ const msgid = msg.msgid ?? msg.MsgId ?? void 0;
27348
27256
  const ctxPayload = channel.reply?.finalizeInboundContext ? channel.reply.finalizeInboundContext({
27349
27257
  Body: body,
27350
27258
  RawBody: rawBody,
@@ -27551,122 +27459,92 @@ var DEFAULT_DOWNLOAD_MAX_BYTES = 20 * 1024 * 1024;
27551
27459
  path2.join("openclaw-baiduapp", "media");
27552
27460
  var DefaultBosClient = import_sdk.default.BosClient;
27553
27461
  var MAX_DOWNLOAD_REDIRECTS = 5;
27554
- async function fetchFileUploadSts(options, deps = {}) {
27555
- assertAccountCanUseChannelApi(options.account);
27556
- const responsePayload = await postAuthenticatedChannelJson(
27557
- options.account,
27558
- "/channel/file/sts",
27559
- {
27560
- sessionId: options.sessionId ?? DEFAULT_BAIDU_APP_SESSION_ID,
27561
- filename: requireSafeDisplayFileName(options.filename),
27562
- fileSize: options.fileSize,
27563
- fileType: normalizeOutboundFileType(options.fileType),
27564
- ...options.md5 ? { md5: options.md5 } : {}
27565
- },
27566
- deps
27567
- );
27568
- const envelope = parseChannelEnvelope(responsePayload, "file STS");
27569
- const data = envelope.data;
27570
- if (!data) {
27571
- throw new Error("file STS response missing data");
27462
+ var EMPTY_QUERY_MD5 = crypto3.createHash("md5").update("").digest("hex");
27463
+ var SKS_BASE_TOKEN_POSITIONS = [12, 37, 5, 23, 48, 15, 62, 33];
27464
+ async function fetchSksCredentials(account, deps = {}) {
27465
+ if (!account.appKey?.trim()) {
27466
+ throw new Error("Cannot fetch SKS credentials without account.appKey");
27467
+ }
27468
+ if (!account.appSecret?.trim()) {
27469
+ throw new Error("Cannot fetch SKS credentials without account.appSecret");
27470
+ }
27471
+ const fetchImpl = deps.fetchImpl ?? fetch;
27472
+ const apiBase = account.apiBase.replace(/\/+$/, "");
27473
+ const pageLid = deps.createPageLid?.() ?? generateSksPageLid();
27474
+ const timestamp = String((deps.now?.() ?? /* @__PURE__ */ new Date()).getTime());
27475
+ const token = createSksRequestToken({ pageLid, timestamp });
27476
+ const url = `${apiBase}/file/sts?ak=${encodeURIComponent(account.appKey)}&sk=${encodeURIComponent(account.appSecret)}&tk=${encodeURIComponent(token)}`;
27477
+ const response = await fetchImpl(url, { method: "POST" });
27478
+ if (!response.ok) {
27479
+ throw new Error(`SKS request failed with HTTP ${response.status}`);
27572
27480
  }
27573
- const fileId = requireNonEmptyString(data.fileId, "file STS data.fileId");
27574
- const reuse = requireBoolean(data.reuse, "file STS data.reuse");
27575
- if (reuse) {
27576
- return { fileId, reuse };
27481
+ let payload;
27482
+ try {
27483
+ payload = await response.json();
27484
+ } catch (error) {
27485
+ throw new Error(`SKS response is not valid JSON: ${formatError(error)}`, { cause: error });
27486
+ }
27487
+ return parseSksCredentialsFromPayload(payload);
27488
+ }
27489
+ function parseSksCredentialsFromPayload(payload) {
27490
+ const parsed = parseSksResponse(payload);
27491
+ if (parsed.status !== 0) {
27492
+ throw new Error(`SKS request failed with status ${parsed.status}`);
27493
+ }
27494
+ if (!parsed.data) {
27495
+ throw new Error("SKS response missing data");
27577
27496
  }
27578
27497
  return {
27579
- fileId,
27580
- reuse,
27581
- sts: parseFileUploadStsCredentials(data.sts),
27582
- bceUrl: requireNonEmptyString(data.bceUrl, "file STS data.bceUrl"),
27583
- bucket: requireNonEmptyString(data.bucket, "file STS data.bucket"),
27584
- bosName: requireNonEmptyString(data.bosName, "file STS data.bosName")
27498
+ ak: requireNonEmptyString(parsed.data.ak, "SKS data.ak"),
27499
+ sk: requireNonEmptyString(parsed.data.sk, "SKS data.sk"),
27500
+ sessionToken: requireNonEmptyString(parsed.data.token, "SKS data.token"),
27501
+ bucketName: requireNonEmptyString(parsed.data.bucketName, "SKS data.bucketName"),
27502
+ prefixPath: sanitizeObjectKeyPrefix(requireNonEmptyString(parsed.data.preFixPath, "SKS data.preFixPath")),
27503
+ endpoint: requireNonEmptyString(parsed.data.bceUrl, "SKS data.bceUrl")
27585
27504
  };
27586
27505
  }
27587
- async function notifyFileUploadComplete(options, deps = {}) {
27588
- assertAccountCanUseChannelApi(options.account);
27589
- if (options.fileIds.length === 0) {
27590
- throw new Error("file complete requires at least one fileId");
27591
- }
27592
- const responsePayload = await postAuthenticatedChannelJson(
27593
- options.account,
27594
- "/channel/file/complete",
27595
- {
27596
- sessionId: options.sessionId ?? DEFAULT_BAIDU_APP_SESSION_ID,
27597
- fileIds: options.fileIds
27598
- },
27599
- deps
27600
- );
27601
- const envelope = parseChannelEnvelope(responsePayload, "file complete");
27602
- const files = extractCompleteFiles(envelope.data);
27603
- const fileIds = new Set(options.fileIds);
27604
- for (const file of files) {
27605
- if (!fileIds.has(file.fileId)) {
27606
- continue;
27607
- }
27608
- if (file.status === -1) {
27609
- throw new Error(`file complete failed for fileId ${file.fileId}`);
27610
- }
27611
- }
27612
- return { files };
27506
+ function createSksRequestToken(params) {
27507
+ const pageLid = requireNonEmptyString(params.pageLid, "SKS pageLid");
27508
+ const timestamp = requireNonEmptyString(params.timestamp, "SKS timestamp");
27509
+ const baseToken = createSksBaseToken(pageLid);
27510
+ const payload = `${baseToken}|${EMPTY_QUERY_MD5}|${timestamp}|${pageLid}`;
27511
+ return `${Buffer.from(payload, "utf8").toString("base64")}-${pageLid}-3`;
27613
27512
  }
27614
- function createBosClient(fileSts, deps = {}) {
27615
- if (!fileSts.sts || !fileSts.bceUrl) {
27616
- throw new Error("Cannot create BOS client without STS credentials");
27617
- }
27513
+ function createBosClient(credentials, deps = {}) {
27618
27514
  const BosClientCtor = deps.bosClientCtor ?? DefaultBosClient;
27619
27515
  return new BosClientCtor({
27620
- endpoint: fileSts.bceUrl,
27621
- sessionToken: fileSts.sts.token,
27516
+ endpoint: credentials.endpoint,
27517
+ sessionToken: credentials.sessionToken,
27622
27518
  credentials: {
27623
- ak: fileSts.sts.ak,
27624
- sk: fileSts.sts.sk
27519
+ ak: credentials.ak,
27520
+ sk: credentials.sk
27625
27521
  }
27626
27522
  });
27627
27523
  }
27628
27524
  async function uploadLocalFileToBos(options, deps = {}) {
27629
27525
  const localFile = await assertUploadableLocalFile(options.filePath);
27526
+ const credentials = await fetchSksCredentials(options.account, deps);
27527
+ const client = createBosClient(credentials, deps);
27630
27528
  const sourceName = options.fileName ?? path2.basename(localFile);
27631
- const fileName = requireSafeDisplayFileName(sourceName);
27632
- const [fileBuffer, fileStat] = await Promise.all([fs2.readFile(localFile), fs2.stat(localFile)]);
27633
- const md5 = crypto.createHash("md5").update(fileBuffer).digest("hex");
27634
- const fileType = inferOutboundFileType(fileName);
27635
- const fileSts = await fetchFileUploadSts(
27636
- {
27637
- account: options.account,
27638
- sessionId: options.sessionId,
27639
- filename: fileName,
27640
- fileSize: fileStat.size,
27641
- fileType,
27642
- md5
27643
- },
27644
- deps
27645
- );
27646
- if (!fileSts.reuse) {
27647
- const bucketName = requireNonEmptyString(fileSts.bucket, "file STS bucket");
27648
- const key = requireNonEmptyString(fileSts.bosName, "file STS bosName");
27649
- const client = createBosClient(fileSts, deps);
27650
- const uploadOptions = options.contentType?.trim() ? {
27651
- "Content-Type": options.contentType.trim()
27652
- } : void 0;
27653
- await client.putObjectFromFile(bucketName, key, localFile, uploadOptions);
27654
- }
27655
- await notifyFileUploadComplete(
27656
- {
27657
- account: options.account,
27658
- sessionId: options.sessionId,
27659
- fileIds: [fileSts.fileId]
27660
- },
27661
- deps
27662
- );
27529
+ const sanitizedFileName = sanitizeFileName(sourceName);
27530
+ const key = buildBosObjectKey({
27531
+ prefixPath: credentials.prefixPath,
27532
+ fileName: sanitizedFileName,
27533
+ now: deps.now
27534
+ });
27535
+ const uploadOptions = options.contentType?.trim() ? {
27536
+ "Content-Type": options.contentType.trim()
27537
+ } : void 0;
27538
+ const [, fileStat] = await Promise.all([
27539
+ client.putObjectFromFile(credentials.bucketName, key, localFile, uploadOptions),
27540
+ fs2.stat(localFile)
27541
+ ]);
27663
27542
  return {
27664
- fileId: fileSts.fileId,
27665
- bucketName: fileSts.bucket,
27666
- key: fileSts.bosName,
27667
- fileName,
27668
- fileSize: fileStat.size,
27669
- reuse: fileSts.reuse
27543
+ bucketName: credentials.bucketName,
27544
+ key,
27545
+ url: client.generateUrl(credentials.bucketName, key),
27546
+ fileName: sanitizedFileName,
27547
+ fileSize: fileStat.size
27670
27548
  };
27671
27549
  }
27672
27550
  async function downloadInboundFileToTemp(options, deps = {}) {
@@ -27764,93 +27642,38 @@ async function pruneExpiredTempFiles(deps = {}) {
27764
27642
  await walk(tempDir);
27765
27643
  return { deletedFiles };
27766
27644
  }
27767
- async function postAuthenticatedChannelJson(account, pathname, bodyPayload, deps) {
27768
- const fetchImpl = deps.fetchImpl ?? fetch;
27769
- const now = deps.now?.() ?? /* @__PURE__ */ new Date();
27770
- const timestamp = String(Math.floor(now.getTime() / 1e3));
27771
- const nonce = (deps.generateNonceImpl ?? generateNonce)();
27772
- const authorization = buildAuthorizationHeader({
27773
- ak: account.appKey ?? "",
27774
- sk: account.appSecret ?? "",
27775
- timestamp,
27776
- nonce
27777
- });
27778
- const url = new URL(`${account.apiBase.replace(/\/+$/, "")}${pathname}`);
27779
- url.searchParams.set("ak", account.appKey ?? "");
27780
- url.searchParams.set("timestamp", timestamp);
27781
- url.searchParams.set("nonce", nonce);
27782
- const response = await fetchImpl(url.toString(), {
27783
- method: "POST",
27784
- headers: {
27785
- "Authorization": authorization,
27786
- "Content-Type": "application/json"
27787
- },
27788
- body: JSON.stringify(bodyPayload)
27789
- });
27790
- if (!response.ok) {
27791
- throw new Error(`channel request failed with HTTP ${response.status}`);
27792
- }
27793
- try {
27794
- return await response.json();
27795
- } catch (error) {
27796
- throw new Error(`channel response is not valid JSON: ${formatError(error)}`, { cause: error });
27797
- }
27798
- }
27799
- function parseChannelEnvelope(payload, label) {
27645
+ function parseSksResponse(payload) {
27800
27646
  if (!payload || typeof payload !== "object") {
27801
- throw new Error(`${label} response must be an object`);
27647
+ throw new Error("SKS response must be an object");
27802
27648
  }
27803
27649
  const record = payload;
27804
- const code = record.code;
27805
- if (typeof code !== "number") {
27806
- throw new Error(`${label} response missing numeric code`);
27807
- }
27808
- if (code !== 0) {
27809
- const msg = typeof record.msg === "string" ? record.msg : "unknown error";
27810
- throw new Error(`${label} request failed with code ${code}: ${msg}`);
27811
- }
27650
+ const status = typeof record.code === "number" ? record.code : typeof record.status === "number" ? record.status : void 0;
27812
27651
  const data = record.data;
27813
27652
  return {
27814
- code,
27815
- msg: typeof record.msg === "string" ? record.msg : void 0,
27816
- data: data && typeof data === "object" ? data : void 0
27653
+ status,
27654
+ data: data && typeof data === "object" ? {
27655
+ ak: data.ak,
27656
+ sk: data.sk,
27657
+ token: data.token,
27658
+ bucketName: data.bucketName,
27659
+ preFixPath: data.preFixPath,
27660
+ bceUrl: data.bceUrl
27661
+ } : void 0
27817
27662
  };
27818
27663
  }
27819
- function parseFileUploadStsCredentials(payload) {
27820
- if (!payload || typeof payload !== "object") {
27821
- throw new Error("file STS data.sts is required");
27822
- }
27823
- const record = payload;
27824
- return {
27825
- ak: requireNonEmptyString(record.ak, "file STS data.sts.ak"),
27826
- sk: requireNonEmptyString(record.sk, "file STS data.sts.sk"),
27827
- token: requireNonEmptyString(record.token, "file STS data.sts.token"),
27828
- expireAt: requireNumber(record.expireAt, "file STS data.sts.expireAt")
27829
- };
27664
+ function generateSksPageLid() {
27665
+ return crypto3.randomBytes(16).toString("hex");
27830
27666
  }
27831
- function extractCompleteFiles(payload) {
27832
- const files = payload?.files;
27833
- if (!Array.isArray(files)) {
27834
- return [];
27835
- }
27836
- return files.map((file, index2) => {
27837
- if (!file || typeof file !== "object") {
27838
- throw new Error(`file complete data.files[${index2}] must be an object`);
27667
+ function createSksBaseToken(pageLid) {
27668
+ const pageLidHash = crypto3.createHash("sha256").update(pageLid).digest("hex");
27669
+ const characters = SKS_BASE_TOKEN_POSITIONS.map((position) => {
27670
+ const character = pageLidHash[position];
27671
+ if (!character) {
27672
+ throw new Error(`SKS base token position is out of range: ${position}`);
27839
27673
  }
27840
- const record = file;
27841
- return {
27842
- fileId: requireNonEmptyString(record.fileId, `file complete data.files[${index2}].fileId`),
27843
- status: requireNumber(record.status, `file complete data.files[${index2}].status`)
27844
- };
27674
+ return character;
27845
27675
  });
27846
- }
27847
- function assertAccountCanUseChannelApi(account) {
27848
- if (!account.appKey?.trim()) {
27849
- throw new Error("Cannot call channel API without account.appKey");
27850
- }
27851
- if (!account.appSecret?.trim()) {
27852
- throw new Error("Cannot call channel API without account.appSecret");
27853
- }
27676
+ return characters.join("");
27854
27677
  }
27855
27678
  function requireNonEmptyString(value, label) {
27856
27679
  if (typeof value !== "string" || !value.trim()) {
@@ -27858,19 +27681,36 @@ function requireNonEmptyString(value, label) {
27858
27681
  }
27859
27682
  return value.trim();
27860
27683
  }
27861
- function requireBoolean(value, label) {
27862
- if (typeof value !== "boolean") {
27863
- throw new Error(`${label} must be a boolean`);
27684
+ function sanitizeObjectKeyPrefix(prefixPath) {
27685
+ const normalized = prefixPath.replace(/\\/g, "/").trim();
27686
+ const segments = normalized.split("/").map((segment) => segment.trim()).filter(Boolean);
27687
+ if (segments.length === 0) {
27688
+ throw new Error("SKS data.preFixPath must contain at least one safe path segment");
27864
27689
  }
27865
- return value;
27690
+ const safeSegments = segments.map((segment) => {
27691
+ if (segment === "." || segment === "..") {
27692
+ throw new Error("SKS data.preFixPath contains path traversal");
27693
+ }
27694
+ return sanitizeObjectKeySegment(segment);
27695
+ });
27696
+ return safeSegments.join("/");
27866
27697
  }
27867
- function requireNumber(value, label) {
27868
- if (typeof value !== "number" || !Number.isFinite(value)) {
27869
- throw new Error(`${label} must be a finite number`);
27698
+ function sanitizeObjectKeySegment(segment) {
27699
+ const sanitized = segment.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
27700
+ if (!sanitized) {
27701
+ throw new Error(`Object key segment is not safe: ${segment}`);
27870
27702
  }
27871
- return value;
27703
+ return sanitized.slice(0, 80);
27704
+ }
27705
+ function sanitizeFileName(fileName) {
27706
+ assertSafeUntrustedFileName(fileName);
27707
+ const parsed = path2.parse(fileName.trim());
27708
+ const safeBase = parsed.name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
27709
+ const safeExt = parsed.ext.replace(/[^a-zA-Z0-9.]+/g, "").slice(0, 16);
27710
+ const baseName = safeBase || "file";
27711
+ return `${baseName.slice(0, 80)}${safeExt}`;
27872
27712
  }
27873
- function requireSafeDisplayFileName(fileName) {
27713
+ function assertSafeUntrustedFileName(fileName) {
27874
27714
  const trimmed = fileName.trim();
27875
27715
  if (!trimmed) {
27876
27716
  throw new Error("Filename cannot be empty");
@@ -27881,18 +27721,14 @@ function requireSafeDisplayFileName(fileName) {
27881
27721
  if (trimmed === "." || trimmed === "..") {
27882
27722
  throw new Error(`Filename is not safe: ${fileName}`);
27883
27723
  }
27884
- return trimmed;
27885
27724
  }
27886
- function normalizeOutboundFileType(fileType) {
27887
- const normalized = fileType.trim().replace(/^\.+/, "").toLowerCase();
27888
- if (!normalized) {
27889
- throw new Error("fileType is required");
27890
- }
27891
- return normalized;
27725
+ function buildBosObjectKey(params) {
27726
+ const timestamp = formatUtcDate(params.now?.() ?? /* @__PURE__ */ new Date());
27727
+ const uniqueId2 = crypto3.randomUUID();
27728
+ return `${params.prefixPath}/${timestamp}/${uniqueId2}-${params.fileName}`;
27892
27729
  }
27893
- function inferOutboundFileType(fileName) {
27894
- const extension = path2.extname(fileName).replace(/^\./, "").toLowerCase();
27895
- return extension || "bin";
27730
+ function formatUtcDate(date) {
27731
+ return date.toISOString().slice(0, 10);
27896
27732
  }
27897
27733
  async function assertUploadableLocalFile(filePath) {
27898
27734
  const resolvedPath = path2.resolve(filePath);
@@ -28017,11 +27853,11 @@ function parseContentDispositionFileName(contentDisposition) {
28017
27853
  }
28018
27854
  function resolveDownloadFileName(params) {
28019
27855
  const candidate = params.explicitFileName ?? params.headerFileName ?? params.urlFileName ?? "file.bin";
28020
- return requireSafeDisplayFileName(candidate);
27856
+ return sanitizeFileName(candidate);
28021
27857
  }
28022
27858
  function buildTempFilePath(params) {
28023
27859
  const timestamp = (params.now?.() ?? /* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
28024
- return path2.join(params.tempDir, `${timestamp}-${crypto.randomUUID()}-${params.fileName}`);
27860
+ return path2.join(params.tempDir, `${timestamp}-${crypto3.randomUUID()}-${params.fileName}`);
28025
27861
  }
28026
27862
  async function ensurePluginTempDir(resolveTmpDir) {
28027
27863
  const baseTmpDir = resolveTmpDir?.() ?? resolvePreferredOpenClawTmpDir();
@@ -28082,12 +27918,12 @@ function normalizeWebhookPath(raw) {
28082
27918
  function jsonOk(res, body) {
28083
27919
  res.statusCode = 200;
28084
27920
  res.setHeader("Content-Type", "application/json; charset=utf-8");
28085
- res.end(JSON.stringify({ code: 0, msg: "success", data: body }));
27921
+ res.end(JSON.stringify({ status: 0, data: body }));
28086
27922
  }
28087
27923
  function jsonError(res, message, statusCode = 200) {
28088
27924
  res.statusCode = statusCode;
28089
27925
  res.setHeader("Content-Type", "application/json; charset=utf-8");
28090
- res.end(JSON.stringify({ code: -1, msg: message, data: {} }));
27926
+ res.end(JSON.stringify({ status: -1, message }));
28091
27927
  }
28092
27928
  async function readRawBody(req, maxBytes) {
28093
27929
  const chunks = [];
@@ -28119,6 +27955,47 @@ async function readRawBody(req, maxBytes) {
28119
27955
  });
28120
27956
  });
28121
27957
  }
27958
+ function parseXmlBody(xml) {
27959
+ const result2 = {};
27960
+ const cdataRegex = /<(\w+)><!\[CDATA\[([\s\S]*?)\]\]><\/\1>/g;
27961
+ let match;
27962
+ while ((match = cdataRegex.exec(xml)) !== null) {
27963
+ const [, key = "", value = ""] = match;
27964
+ result2[key] = value;
27965
+ }
27966
+ const simpleRegex = /<(\w+)>([^<]*)<\/\1>/g;
27967
+ while ((match = simpleRegex.exec(xml)) !== null) {
27968
+ const [, key = "", value = ""] = match;
27969
+ if (!result2[key]) {
27970
+ result2[key] = value;
27971
+ }
27972
+ }
27973
+ return result2;
27974
+ }
27975
+ function isXmlFormat(raw) {
27976
+ const trimmed = raw.trim();
27977
+ return trimmed.startsWith("<") && trimmed.endsWith(">");
27978
+ }
27979
+ function buildEncryptedJsonReply(params) {
27980
+ const base = params.plaintextJson != null && typeof params.plaintextJson === "object" ? params.plaintextJson : {};
27981
+ const plaintext = JSON.stringify({ ...base, version: PLUGIN_VERSION });
27982
+ const encrypt = encryptBaiduAppPlaintext({
27983
+ encodingAESKey: params.account.encodingAESKey ?? "",
27984
+ plaintext
27985
+ });
27986
+ const msgsignature = computeBaiduAppMsgSignature({
27987
+ token: params.account.token ?? "",
27988
+ timestamp: params.timestamp,
27989
+ nonce: params.nonce,
27990
+ encrypt
27991
+ });
27992
+ return {
27993
+ encrypt,
27994
+ msgsignature,
27995
+ timestamp: params.timestamp,
27996
+ nonce: params.nonce
27997
+ };
27998
+ }
28122
27999
  function resolveQueryParams(req) {
28123
28000
  const url = new URL(req.url ?? "/", "http://localhost");
28124
28001
  return url.searchParams;
@@ -28127,16 +28004,8 @@ function resolvePath(req) {
28127
28004
  const url = new URL(req.url ?? "/", "http://localhost");
28128
28005
  return normalizeWebhookPath(url.pathname || "/");
28129
28006
  }
28130
- function resolveBearerToken(req) {
28131
- const authorization = req.headers.authorization ?? req.headers.Authorization;
28132
- if (Array.isArray(authorization)) {
28133
- return "";
28134
- }
28135
- const value = typeof authorization === "string" ? authorization.trim() : "";
28136
- if (!value.toLowerCase().startsWith("bearer ")) {
28137
- return "";
28138
- }
28139
- return value.slice(7).trim();
28007
+ function resolveSignatureParam(params) {
28008
+ return params.get("msg_signature") ?? params.get("msgsignature") ?? params.get("signature") ?? "";
28140
28009
  }
28141
28010
  function buildLogger(target) {
28142
28011
  return createLogger("openclaw-baiduapp", {
@@ -28204,49 +28073,50 @@ async function downloadInboundFiles(params) {
28204
28073
  }
28205
28074
  };
28206
28075
  }
28207
- function parseV2MsgToInbound(inner, outer) {
28208
- const list = Array.isArray(inner.list) ? inner.list : [];
28209
- const textItem = list.find(
28210
- (item) => item && typeof item === "object" && item.type === "text"
28211
- );
28212
- const fileItems = list.filter(
28213
- (item) => item && typeof item === "object" && item.type === "file"
28214
- );
28215
- const textContent = textItem?.data?.text?.content ?? "";
28216
- const files = fileItems.map((f) => ({ url: f.data.fileId, fileType: "file" }));
28217
- return {
28218
- msgtype: "text",
28219
- msgid: typeof outer.msgid === "string" ? outer.msgid : void 0,
28220
- agentid: typeof outer.agentid === "string" ? outer.agentid : void 0,
28221
- text: textContent ? { content: textContent } : void 0,
28222
- ...files.length > 0 ? { files } : {}
28223
- };
28224
- }
28225
- function parseBaiduAppCandidates(params) {
28226
- const results = [];
28227
- let outer = {};
28076
+ function parseBaiduAppPlainMessage(raw) {
28077
+ const trimmed = raw.trim();
28078
+ if (trimmed.startsWith("<") && trimmed.endsWith(">")) {
28079
+ const xmlData = parseXmlBody(trimmed);
28080
+ return {
28081
+ msgtype: xmlData.MsgType,
28082
+ MsgType: xmlData.MsgType,
28083
+ msgid: xmlData.MsgId,
28084
+ MsgId: xmlData.MsgId,
28085
+ content: xmlData.Content,
28086
+ Content: xmlData.Content,
28087
+ from: xmlData.FromUserName ? { appkey: xmlData.FromUserName } : void 0,
28088
+ ToUserName: xmlData.ToUserName,
28089
+ CreateTime: xmlData.CreateTime ? Number(xmlData.CreateTime) : void 0,
28090
+ BotID: xmlData.BotID ? Number(xmlData.BotID) : void 0,
28091
+ Event: xmlData.Event
28092
+ };
28093
+ }
28228
28094
  try {
28229
- const parsed = JSON.parse(params.raw);
28230
- if (parsed && typeof parsed === "object") {
28231
- outer = parsed;
28095
+ const parsed = JSON.parse(trimmed);
28096
+ if (!parsed || typeof parsed !== "object") {
28097
+ return {};
28232
28098
  }
28099
+ return parsed;
28233
28100
  } catch {
28234
- outer = {};
28101
+ return {};
28235
28102
  }
28236
- let inner = {};
28237
- if (typeof outer.msg === "string") {
28103
+ }
28104
+ function decryptBaiduAppCandidates(params) {
28105
+ const results = [];
28106
+ for (const candidate of params.candidates) {
28107
+ if (!candidate.account.encodingAESKey) {
28108
+ continue;
28109
+ }
28238
28110
  try {
28239
- const parsedInner = JSON.parse(outer.msg);
28240
- if (parsedInner && typeof parsedInner === "object") {
28241
- inner = parsedInner;
28242
- }
28111
+ const plaintext = decryptBaiduAppEncrypted({
28112
+ encodingAESKey: candidate.account.encodingAESKey,
28113
+ encrypt: params.encrypt
28114
+ });
28115
+ const msg = parseBaiduAppPlainMessage(plaintext);
28116
+ results.push({ target: candidate, plaintext, msg });
28243
28117
  } catch {
28244
- inner = {};
28245
28118
  }
28246
28119
  }
28247
- for (const candidate of params.candidates) {
28248
- results.push({ target: candidate, msg: parseV2MsgToInbound(inner, outer) });
28249
- }
28250
28120
  return results;
28251
28121
  }
28252
28122
  function selectDecryptedTarget(params) {
@@ -28263,9 +28133,8 @@ async function processBaiduAppInboundMessage(params) {
28263
28133
  const { target, msg } = params;
28264
28134
  const logger3 = buildLogger(target);
28265
28135
  target.statusSink?.({ lastInboundAt: Date.now() });
28266
- const msgtype = String(msg.msgtype ?? "").toLowerCase();
28267
- const msgid = msg.msgid ? String(msg.msgid) : void 0;
28268
- const agentId = extractAgentId(msg);
28136
+ const msgtype = String(msg.msgtype ?? msg.MsgType ?? "").toLowerCase();
28137
+ const msgid = msg.msgid ?? msg.MsgId ? String(msg.msgid ?? msg.MsgId) : void 0;
28269
28138
  logger3.info(`inbound: type=${msgtype || "unknown"} msgid=${msgid ?? "none"} account=${target.account.accountId}`);
28270
28139
  if (!canDispatchBaiduAppInboundMessage(msg)) {
28271
28140
  logger3.warn(`inbound message skipped: type=${msgtype || "unknown"} reason=no-dispatchable-content`);
@@ -28273,11 +28142,6 @@ async function processBaiduAppInboundMessage(params) {
28273
28142
  }
28274
28143
  const inboundFileResult = msgtype === "text" ? await downloadInboundFiles({ msg, logger: logger3, runtime: target.runtime }) : { localFiles: [], diagnostic: {} };
28275
28144
  const inboundMediaFiles = inboundFileResult.localFiles;
28276
- const agentAccount = resolveAgentAccount({
28277
- baseAccount: target.account,
28278
- cfg: target.config,
28279
- agentId
28280
- });
28281
28145
  const core = tryGetBaiduAppRuntime();
28282
28146
  if (core) {
28283
28147
  logger3.info(`agent dispatch started: canSendActive=${target.account.canSendActive}`);
@@ -28290,9 +28154,8 @@ async function processBaiduAppInboundMessage(params) {
28290
28154
  );
28291
28155
  target.statusSink?.({ lastOutboundAt: Date.now() });
28292
28156
  if (target.account.canSendActive) {
28293
- sendBaiduAppMessage(agentAccount, text, {
28294
- replyToMsgId: msgid,
28295
- agentid: agentId,
28157
+ sendBaiduAppMessage(target.account, text, {
28158
+ msgid,
28296
28159
  chunkKey: currentChunkKey
28297
28160
  }).then((result2) => {
28298
28161
  if (!result2.ok) {
@@ -28315,7 +28178,7 @@ async function processBaiduAppInboundMessage(params) {
28315
28178
  };
28316
28179
  dispatchBaiduAppMessage({
28317
28180
  cfg: target.config,
28318
- account: agentAccount,
28181
+ account: target.account,
28319
28182
  msg,
28320
28183
  core,
28321
28184
  hooks,
@@ -28357,43 +28220,53 @@ async function handleBaiduAppWebhookRequest(req, res) {
28357
28220
  const query = resolveQueryParams(req);
28358
28221
  const timestamp = query.get("timestamp") ?? "";
28359
28222
  const nonce = query.get("nonce") ?? "";
28360
- const ak = query.get("ak") ?? "";
28361
- const token = resolveBearerToken(req);
28223
+ const signature = resolveSignatureParam(query);
28362
28224
  const primary = targets[0];
28363
28225
  const logger3 = buildLogger(primary);
28364
28226
  if (req.method === "GET") {
28365
28227
  const echostr = query.get("echostr") ?? "";
28366
- if (!ak || !timestamp || !nonce || !token || !echostr) {
28228
+ if (!timestamp || !nonce || !signature || !echostr) {
28367
28229
  jsonError(res, "missing query params", 400);
28368
28230
  return true;
28369
28231
  }
28370
- const tokenMatched2 = targets.filter((candidate) => {
28371
- if (!candidate.account.appKey || !candidate.account.appSecret) {
28372
- return false;
28373
- }
28374
- if (candidate.account.appKey !== ak) {
28232
+ const signatureMatched2 = targets.filter((candidate) => {
28233
+ if (!candidate.account.token) {
28375
28234
  return false;
28376
28235
  }
28377
- return verifyAKSKBearerToken({
28378
- ak: candidate.account.appKey,
28379
- sk: candidate.account.appSecret,
28236
+ return verifyBaiduAppSignature({
28237
+ token: candidate.account.token,
28380
28238
  timestamp,
28381
28239
  nonce,
28382
- token
28240
+ encrypt: echostr,
28241
+ signature
28383
28242
  });
28384
28243
  });
28385
- if (tokenMatched2.length === 0) {
28244
+ if (signatureMatched2.length === 0) {
28245
+ jsonError(res, "unauthorized");
28246
+ return true;
28247
+ }
28248
+ const decryptable2 = signatureMatched2.filter((candidate) => Boolean(candidate.account.encodingAESKey));
28249
+ if (decryptable2.length === 0) {
28386
28250
  jsonError(res, "unauthorized");
28387
28251
  return true;
28388
28252
  }
28389
- jsonOk(res, echostr);
28253
+ const decryptedCandidates2 = decryptBaiduAppCandidates({
28254
+ candidates: decryptable2,
28255
+ encrypt: echostr
28256
+ });
28257
+ if (decryptedCandidates2.length === 0) {
28258
+ jsonError(res, "decrypt failed");
28259
+ return true;
28260
+ }
28261
+ const selected2 = selectDecryptedTarget({ candidates: decryptedCandidates2, logger: logger3 });
28262
+ jsonOk(res, selected2.plaintext);
28390
28263
  return true;
28391
28264
  }
28392
28265
  if (req.method !== "POST") {
28393
28266
  jsonError(res, "Method Not Allowed", 405);
28394
28267
  return true;
28395
28268
  }
28396
- if (!ak || !timestamp || !nonce || !token) {
28269
+ if (!timestamp || !nonce || !signature) {
28397
28270
  jsonError(res, "missing query params");
28398
28271
  return true;
28399
28272
  }
@@ -28403,56 +28276,90 @@ async function handleBaiduAppWebhookRequest(req, res) {
28403
28276
  return true;
28404
28277
  }
28405
28278
  const rawBody = body.raw;
28406
- try {
28407
- JSON.parse(rawBody);
28408
- logger3.info("inbound json parsed");
28409
- } catch {
28410
- logger3.warn("inbound payload parse failed: not valid json");
28411
- jsonError(res, "invalid payload format");
28279
+ let encrypt = "";
28280
+ let msgSignature = signature;
28281
+ let msgTimestamp = timestamp;
28282
+ let msgNonce = nonce;
28283
+ if (isXmlFormat(rawBody)) {
28284
+ const xmlData = parseXmlBody(rawBody);
28285
+ encrypt = xmlData.Encrypt ?? "";
28286
+ msgSignature = xmlData.MsgSignature ?? signature;
28287
+ msgTimestamp = xmlData.TimeStamp ?? timestamp;
28288
+ msgNonce = xmlData.Nonce ?? nonce;
28289
+ logger3.info(`inbound xml parsed: hasEncrypt=${Boolean(encrypt)}, msg_signature=${msgSignature ? "yes" : "no"}`);
28290
+ } else {
28291
+ try {
28292
+ const record = JSON.parse(rawBody);
28293
+ encrypt = String(record.encrypt ?? record.Encrypt ?? "");
28294
+ logger3.info(`inbound json parsed: hasEncrypt=${Boolean(encrypt)}`);
28295
+ } catch {
28296
+ logger3.warn(`inbound payload parse failed: not valid xml or json`);
28297
+ jsonError(res, "invalid payload format");
28298
+ return true;
28299
+ }
28300
+ }
28301
+ if (!encrypt) {
28302
+ jsonError(res, "missing encrypt");
28412
28303
  return true;
28413
28304
  }
28414
- const tokenMatched = targets.filter((candidate) => {
28415
- if (!candidate.account.appKey || !candidate.account.appSecret) {
28305
+ const signatureMatched = targets.filter((candidate) => {
28306
+ if (!candidate.account.token) {
28416
28307
  return false;
28417
28308
  }
28418
- if (candidate.account.appKey !== ak) {
28419
- return false;
28420
- }
28421
- return verifyAKSKBearerToken({
28422
- ak: candidate.account.appKey,
28423
- sk: candidate.account.appSecret,
28424
- timestamp,
28425
- nonce,
28426
- token
28309
+ return verifyBaiduAppSignature({
28310
+ token: candidate.account.token,
28311
+ timestamp: msgTimestamp,
28312
+ nonce: msgNonce,
28313
+ encrypt,
28314
+ signature: msgSignature
28427
28315
  });
28428
28316
  });
28429
- if (tokenMatched.length === 0) {
28430
- logger3.warn(`bearer token verification failed: checked ${targets.length} account(s), none matched`);
28317
+ if (signatureMatched.length === 0) {
28318
+ logger3.warn(`signature verification failed: checked ${targets.length} account(s), none matched`);
28431
28319
  jsonError(res, "unauthorized");
28432
28320
  return true;
28433
28321
  }
28434
- logger3.debug(`bearer token verified: ${tokenMatched.length} account(s) matched`);
28435
- const decryptedCandidates = parseBaiduAppCandidates({
28436
- candidates: tokenMatched,
28437
- raw: rawBody
28322
+ logger3.debug(`signature verified: ${signatureMatched.length} account(s) matched`);
28323
+ const decryptable = signatureMatched.filter((candidate) => Boolean(candidate.account.encodingAESKey));
28324
+ if (decryptable.length === 0) {
28325
+ logger3.warn(`no account has encodingAESKey configured`);
28326
+ jsonError(res, "openclaw-baiduapp not configured");
28327
+ return true;
28328
+ }
28329
+ const decryptedCandidates = decryptBaiduAppCandidates({
28330
+ candidates: decryptable,
28331
+ encrypt
28438
28332
  });
28333
+ if (decryptedCandidates.length === 0) {
28334
+ logger3.warn(`decrypt failed for all ${decryptable.length} candidate account(s)`);
28335
+ jsonError(res, "decrypt failed");
28336
+ return true;
28337
+ }
28439
28338
  const selected = selectDecryptedTarget({ candidates: decryptedCandidates, logger: logger3 });
28440
28339
  const target = selected.target;
28441
- if (!target.account.configured || !target.account.appKey || !target.account.appSecret) {
28340
+ if (!target.account.configured || !target.account.token || !target.account.encodingAESKey) {
28442
28341
  logger3.warn(`selected account ${target.account.accountId} not fully configured`);
28443
28342
  jsonError(res, "openclaw-baiduapp not configured");
28444
28343
  return true;
28445
28344
  }
28446
- await processBaiduAppInboundMessage({
28345
+ const reply = await processBaiduAppInboundMessage({
28447
28346
  target,
28448
28347
  msg: selected.msg
28449
28348
  });
28450
- jsonOk(res, {});
28349
+ jsonOk(
28350
+ res,
28351
+ buildEncryptedJsonReply({
28352
+ account: target.account,
28353
+ plaintextJson: reply,
28354
+ nonce: msgNonce,
28355
+ timestamp: msgTimestamp
28356
+ })
28357
+ );
28451
28358
  return true;
28452
28359
  }
28453
28360
 
28454
28361
  // src/poller.ts
28455
- var DEFAULT_POLL_INTERVAL_MS = 3e3;
28362
+ var DEFAULT_POLL_INTERVAL_MS = 1e3;
28456
28363
  var DEFAULT_POLL_REQUEST_TIMEOUT_MS = 1e4;
28457
28364
  var accountPollers = /* @__PURE__ */ new Map();
28458
28365
  function buildPollingTextInboundMessage(content) {
@@ -28463,36 +28370,21 @@ function buildPollingTextInboundMessage(content) {
28463
28370
  }
28464
28371
  };
28465
28372
  }
28466
- function parseTextAndFilesFromList(list) {
28467
- const textItem = list.find((entry) => entry.type === "text");
28468
- const fileItems = list.filter((entry) => entry.type === "file");
28469
- const content = textItem?.type === "text" ? textItem.data.text.content : void 0;
28470
- const files = fileItems.map((file) => {
28471
- const fileId = file.data.file.fileId;
28472
- return typeof fileId === "string" && fileId.trim() ? { url: fileId, fileType: "file" } : null;
28473
- }).filter((file) => file != null);
28474
- return { content, files };
28475
- }
28476
28373
  async function dispatchPendingPollingMessages(data, target) {
28477
- console.log(data);
28478
28374
  if (!target || data.length === 0) {
28479
28375
  return;
28480
28376
  }
28481
28377
  for (const item of data) {
28482
- const list = Array.isArray(item.list) ? item.list : [];
28483
- const { content, files } = parseTextAndFilesFromList(list);
28484
- console.log({ content, files });
28485
- if (typeof content !== "string" && files.length === 0) {
28378
+ if (String(item.msgtype).toLowerCase() !== "text") {
28379
+ continue;
28380
+ }
28381
+ const content = item.data?.content;
28382
+ if (typeof content !== "string" || content.length === 0) {
28486
28383
  continue;
28487
28384
  }
28488
28385
  await processBaiduAppInboundMessage({
28489
28386
  target,
28490
- msg: {
28491
- ...buildPollingTextInboundMessage(typeof content === "string" ? content : ""),
28492
- msgid: typeof item.msgId === "string" ? item.msgId : void 0,
28493
- agentid: typeof item.agentId === "string" ? item.agentId : void 0,
28494
- ...files.length > 0 ? { files } : {}
28495
- }
28387
+ msg: buildPollingTextInboundMessage(content)
28496
28388
  });
28497
28389
  }
28498
28390
  }
@@ -28547,29 +28439,12 @@ function createAbortSignalController(params) {
28547
28439
  };
28548
28440
  }
28549
28441
  async function pollBaiduAppChatlistOnce(account, loggerOptions, requestOptions) {
28550
- const endpoint = `${account.apiBase}/channel/msg/poll`;
28551
- const logger3 = createLogger("openclaw-baiduapp:poller", loggerOptions);
28552
- const timestamp = String(Math.floor(Date.now() / 1e3));
28553
- const nonce = generateNonce();
28554
- const authorization = buildAuthorizationHeader({
28555
- ak: account.appKey ?? "",
28556
- sk: account.appSecret ?? "",
28557
- timestamp,
28558
- nonce
28559
- });
28442
+ const endpoint = `${account.apiBase}/chat/demo/chatlist`;
28560
28443
  const query = new URLSearchParams({
28561
28444
  ak: account.appKey ?? "",
28562
- timestamp,
28563
- nonce
28445
+ sk: account.appSecret ?? ""
28564
28446
  });
28565
28447
  const url = `${endpoint}?${query.toString()}`;
28566
- const payload = {
28567
- sessionId: "agent:main:main",
28568
- num: 5,
28569
- version: PLUGIN_VERSION
28570
- };
28571
- const body = JSON.stringify(payload);
28572
- console.log("start poll", url);
28573
28448
  const requestSignal = createAbortSignalController({
28574
28449
  signal: requestOptions?.signal,
28575
28450
  timeoutMs: requestOptions?.timeoutMs
@@ -28577,13 +28452,8 @@ async function pollBaiduAppChatlistOnce(account, loggerOptions, requestOptions)
28577
28452
  let response;
28578
28453
  try {
28579
28454
  response = await (requestOptions?.fetchImpl ?? fetch)(url, {
28580
- method: "POST",
28581
- body,
28582
- signal: requestSignal.signal,
28583
- headers: {
28584
- "Authorization": authorization,
28585
- "Content-Type": "application/json"
28586
- }
28455
+ method: "GET",
28456
+ signal: requestSignal.signal
28587
28457
  });
28588
28458
  } catch (error) {
28589
28459
  requestSignal.cleanup();
@@ -28636,13 +28506,10 @@ async function pollBaiduAppChatlistOnce(account, loggerOptions, requestOptions)
28636
28506
  }
28637
28507
  });
28638
28508
  }
28639
- if (parsed.code !== 0) {
28640
- logger3.debug(`Baidu poll returned non-zero code=${String(parsed.code)}, message=${parsed.message}`);
28641
- }
28642
- const msgList = Array.isArray(parsed.data?.msgList) ? parsed.data.msgList : [];
28509
+ const data = Array.isArray(parsed.data) ? parsed.data : [];
28643
28510
  return buildPollResult({
28644
28511
  ok: true,
28645
- data: msgList
28512
+ data
28646
28513
  });
28647
28514
  }
28648
28515
  function scheduleNextPoll(account, state) {
@@ -28758,33 +28625,16 @@ function resolveOutboundLocalMediaPath(mediaUrl) {
28758
28625
  }
28759
28626
  return trimmed;
28760
28627
  }
28628
+ function inferBaiduOutboundFileType(params) {
28629
+ const ext = path2.extname(params.mediaPath).toLowerCase();
28630
+ return ext.startsWith(".") ? ext.slice(1) : ext || "bin";
28631
+ }
28761
28632
  function buildOutboundMediaPayload(params) {
28762
28633
  const caption = params.caption?.trim();
28763
- const mediaItem = params.externalUrl ? {
28764
- type: "external_url",
28765
- data: {
28766
- externalUrl: {
28767
- url: params.externalUrl
28768
- }
28769
- }
28770
- } : {
28771
- type: "file",
28772
- data: {
28773
- file: {
28774
- fileId: params.fileId ?? ""
28775
- }
28776
- }
28777
- };
28778
28634
  return {
28779
- list: [
28780
- ...caption ? [{
28781
- type: "text",
28782
- data: {
28783
- text: { content: caption }
28784
- }
28785
- }] : [],
28786
- mediaItem
28787
- ]
28635
+ msgtype: "text",
28636
+ ...caption ? { text: { content: caption } } : {},
28637
+ files: [{ url: params.uploadedUrl, fileType: params.fileType }]
28788
28638
  };
28789
28639
  }
28790
28640
  function resolveDirectOutboundFiles(files) {
@@ -29021,10 +28871,7 @@ var baiduAppPlugin = {
29021
28871
  };
29022
28872
  }
29023
28873
  try {
29024
- const result2 = await sendBaiduAppMessage(account, params.text, {
29025
- agentid: account.accountId,
29026
- isActive: true
29027
- });
28874
+ const result2 = await sendBaiduAppMessage(account, params.text);
29028
28875
  return {
29029
28876
  channel: "openclaw-baiduapp",
29030
28877
  ok: result2.ok,
@@ -29067,15 +28914,14 @@ var baiduAppPlugin = {
29067
28914
  account,
29068
28915
  buildOutboundMediaPayload({
29069
28916
  caption: params.text,
29070
- externalUrl: remoteUrl
29071
- }),
29072
- { agentid: account.accountId, isActive: true }
28917
+ uploadedUrl: remoteUrl,
28918
+ fileType: inferBaiduOutboundFileType({ mediaPath: remoteUrl })
28919
+ })
29073
28920
  );
29074
28921
  return {
29075
28922
  channel: "openclaw-baiduapp",
29076
- ok: result2.ok,
29077
- messageId: result2.msgid ?? "",
29078
- error: result2.ok ? void 0 : new Error(result2.errmsg ?? "send failed")
28923
+ ok: true,
28924
+ messageId: result2.msgid ?? ""
29079
28925
  };
29080
28926
  } catch (err) {
29081
28927
  return {
@@ -29108,9 +28954,11 @@ var baiduAppPlugin = {
29108
28954
  account,
29109
28955
  buildOutboundMediaPayload({
29110
28956
  caption: params.text,
29111
- fileId: uploaded.fileId
29112
- }),
29113
- { agentid: account.accountId, isActive: true }
28957
+ uploadedUrl: uploaded.url,
28958
+ fileType: inferBaiduOutboundFileType({
28959
+ mediaPath: uploaded.fileName || localMediaPath
28960
+ })
28961
+ })
29114
28962
  );
29115
28963
  return {
29116
28964
  channel: "openclaw-baiduapp",
@@ -29132,18 +28980,6 @@ var baiduAppPlugin = {
29132
28980
  }
29133
28981
  }
29134
28982
  },
29135
- auth: {
29136
- login: async (params) => {
29137
- void params.channelInput;
29138
- const { loginBaiduApp: loginBaiduApp2 } = await Promise.resolve().then(() => (init_login(), login_exports));
29139
- await loginBaiduApp2({
29140
- cfg: params.cfg,
29141
- accountId: params.accountId,
29142
- runtime: params.runtime,
29143
- verbose: params.verbose
29144
- });
29145
- }
29146
- },
29147
28983
  gateway: {
29148
28984
  startAccount: async (ctx) => {
29149
28985
  ctx.setStatus?.({ accountId: ctx.accountId });
@@ -29181,19 +29017,21 @@ var baiduAppPlugin = {
29181
29017
  existing();
29182
29018
  }
29183
29019
  unregisterHooks.set(ctx.accountId, unregister);
29184
- startAccountPolling({
29185
- account,
29186
- dispatchTarget: {
29020
+ if (account.config.pollingEnabled === true) {
29021
+ startAccountPolling({
29187
29022
  account,
29188
- config: ctx.cfg ?? {},
29189
- runtime: runtime2,
29190
- statusSink: (patch) => ctx.setStatus?.({ accountId: ctx.accountId, ...patch })
29191
- },
29192
- onError: (error) => {
29193
- const message = error instanceof Error ? error.message : String(error);
29194
- ctx.log?.error(`[openclaw-baiduapp] polling failed for account ${ctx.accountId}: ${message}`);
29195
- }
29196
- });
29023
+ dispatchTarget: {
29024
+ account,
29025
+ config: ctx.cfg ?? {},
29026
+ runtime: runtime2,
29027
+ statusSink: (patch) => ctx.setStatus?.({ accountId: ctx.accountId, ...patch })
29028
+ },
29029
+ onError: (error) => {
29030
+ const message = error instanceof Error ? error.message : String(error);
29031
+ ctx.log?.error(`[openclaw-baiduapp] polling failed for account ${ctx.accountId}: ${message}`);
29032
+ }
29033
+ });
29034
+ }
29197
29035
  ctx.log?.info(
29198
29036
  `[openclaw-baiduapp] webhook registered at ${path4} for account ${ctx.accountId} (canSendActive=${account.canSendActive})`
29199
29037
  );
@@ -29245,7 +29083,7 @@ async function sendMessage(account, options) {
29245
29083
  };
29246
29084
  }
29247
29085
  try {
29248
- const textResult = await sendBaiduAppMessage(account, options.text, { isActive: true });
29086
+ const textResult = await sendBaiduAppMessage(account, options.text);
29249
29087
  return {
29250
29088
  ok: textResult.ok,
29251
29089
  msgid: textResult.msgid,