koishi-plugin-aka-ai-generator 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -29,6 +29,36 @@ var import_koishi = require("koishi");
29
29
  var import_fs = require("fs");
30
30
  var import_path = require("path");
31
31
 
32
+ // src/providers/types.ts
33
+ function sanitizeError(error) {
34
+ if (!error) return error;
35
+ if (typeof error === "string") {
36
+ return sanitizeString(error);
37
+ }
38
+ if (Array.isArray(error)) {
39
+ return error.map((item) => sanitizeError(item));
40
+ }
41
+ if (typeof error === "object") {
42
+ const sanitized = {};
43
+ for (const key in error) {
44
+ const lowerKey = key.toLowerCase();
45
+ if (lowerKey.includes("apikey") || lowerKey.includes("api_key") || lowerKey.includes("apikey") || lowerKey === "key" || lowerKey === "authorization" || lowerKey === "token" || lowerKey === "secret" || lowerKey === "password") {
46
+ sanitized[key] = "[REDACTED]";
47
+ continue;
48
+ }
49
+ sanitized[key] = sanitizeError(error[key]);
50
+ }
51
+ return sanitized;
52
+ }
53
+ return error;
54
+ }
55
+ __name(sanitizeError, "sanitizeError");
56
+ function sanitizeString(str) {
57
+ if (typeof str !== "string") return str;
58
+ return str.replace(/key["\s:=]+([a-zA-Z0-9_-]{20,})/gi, 'key="[REDACTED]"').replace(/apikey["\s:=]+([a-zA-Z0-9_-]{20,})/gi, 'apikey="[REDACTED]"').replace(/api_key["\s:=]+([a-zA-Z0-9_-]{20,})/gi, 'api_key="[REDACTED]"').replace(/authorization["\s:=]+(Bearer\s+)?([a-zA-Z0-9_-]{20,})/gi, 'authorization="[REDACTED]"').replace(/Bearer\s+([a-zA-Z0-9_-]{20,})/gi, "Bearer [REDACTED]");
59
+ }
60
+ __name(sanitizeString, "sanitizeString");
61
+
32
62
  // src/providers/yunwu.ts
33
63
  async function downloadImageAsBase64(ctx, url, timeout, logger) {
34
64
  try {
@@ -148,8 +178,9 @@ var YunwuProvider = class {
148
178
  allImages.push(...images);
149
179
  logger.success("云雾图像编辑 API 调用成功", { current: i + 1, total: numImages });
150
180
  } catch (error) {
181
+ const safeMessage = typeof error?.message === "string" ? sanitizeString(error.message) : "未知错误";
151
182
  logger.error("云雾图像编辑 API 调用失败", {
152
- message: error?.message || "未知错误",
183
+ message: safeMessage,
153
184
  code: error?.code,
154
185
  status: error?.response?.status,
155
186
  current: i + 1,
@@ -516,23 +547,25 @@ var GptGodProvider = class {
516
547
  await new Promise((resolve) => setTimeout(resolve, delay));
517
548
  continue;
518
549
  }
550
+ const sanitizedError = sanitizeError(error);
551
+ const safeMessage = typeof error?.message === "string" ? sanitizeString(error.message) : "未知错误";
519
552
  logger.error("GPTGod 图像编辑 API 调用失败", {
520
- message: error?.message || "未知错误",
553
+ message: safeMessage,
521
554
  name: error?.name,
522
555
  code: error?.code,
523
556
  status: error?.response?.status,
524
557
  statusText: error?.response?.statusText,
525
- data: error?.response?.data,
526
- stack: error?.stack,
527
- cause: error?.cause,
558
+ data: sanitizeError(error?.response?.data),
559
+ stack: sanitizeString(error?.stack || ""),
560
+ cause: sanitizeError(error?.cause),
528
561
  attempt,
529
562
  maxRetries,
530
563
  current: i + 1,
531
564
  total: numImages,
532
- // 如果是 axios 错误,通常会有 config 和 request 信息
565
+ // 如果是 axios 错误,通常会有 config 和 request 信息(清理敏感信息)
533
566
  url: error?.config?.url,
534
567
  method: error?.config?.method,
535
- headers: error?.config?.headers
568
+ headers: sanitizeError(error?.config?.headers)
536
569
  });
537
570
  if (error?.cause?.code === "UND_ERR_SOCKET" || error?.message?.includes("other side closed")) {
538
571
  throw new Error("图像处理失败:服务器连接中断,可能是服务器负载过高或网络不稳定,请稍后重试");
@@ -595,8 +628,11 @@ function parseGeminiResponse(response, logger) {
595
628
  return [];
596
629
  }
597
630
  if (response.error) {
598
- logger?.error("Gemini API 返回错误", { error: response.error });
599
- throw new Error(`Gemini API 错误: ${response.error.message || JSON.stringify(response.error)}`);
631
+ const sanitizedError = sanitizeError(response.error);
632
+ logger?.error("Gemini API 返回错误", { error: sanitizedError });
633
+ const errorMessage = response.error.message || JSON.stringify(sanitizedError);
634
+ const safeMessage = sanitizeString(errorMessage);
635
+ throw new Error(`Gemini API 错误: ${safeMessage}`);
600
636
  }
601
637
  if (response.promptFeedback) {
602
638
  const blockReason = response.promptFeedback.blockReason;
@@ -698,8 +734,12 @@ function parseGeminiResponse(response, logger) {
698
734
  }
699
735
  return images;
700
736
  } catch (error) {
701
- logger?.error("解析 Gemini 响应时出错", { error: error.message, stack: error.stack });
702
- throw error;
737
+ const safeMessage = sanitizeString(error?.message || "未知错误");
738
+ const safeStack = sanitizeString(error?.stack || "");
739
+ logger?.error("解析 Gemini 响应时出错", { error: safeMessage, stack: safeStack });
740
+ const sanitizedError = new Error(safeMessage);
741
+ sanitizedError.name = error?.name || "Error";
742
+ throw sanitizedError;
703
743
  }
704
744
  }
705
745
  __name(parseGeminiResponse, "parseGeminiResponse");
@@ -783,11 +823,13 @@ var GeminiProvider = class {
783
823
  }
784
824
  allImages.push(...images);
785
825
  } catch (error) {
826
+ const sanitizedError = sanitizeError(error);
827
+ const safeMessage = typeof error?.message === "string" ? sanitizeString(error.message) : "未知错误";
786
828
  logger.error("Gemini API 调用失败", {
787
- message: error?.message || "未知错误",
829
+ message: safeMessage,
788
830
  code: error?.code,
789
831
  status: error?.response?.status,
790
- responseData: error?.response?.data ? JSON.stringify(error.response.data).substring(0, 500) : void 0,
832
+ responseData: error?.response?.data ? sanitizeString(JSON.stringify(error.response.data).substring(0, 500)) : void 0,
791
833
  current: i + 1,
792
834
  total: numImages
793
835
  });
@@ -795,7 +837,7 @@ var GeminiProvider = class {
795
837
  logger.warn("部分图片生成失败,返回已生成的图片", { generated: allImages.length, requested: numImages });
796
838
  break;
797
839
  }
798
- throw new Error(`图像处理API调用失败: ${error?.message || "未知错误"}`);
840
+ throw new Error(`图像处理API调用失败: ${safeMessage}`);
799
841
  }
800
842
  }
801
843
  if (allImages.length === 0) {
@@ -1122,7 +1164,7 @@ function apply(ctx, config) {
1122
1164
  rateLimitMap.set(userId, userTimestamps);
1123
1165
  }
1124
1166
  __name(updateRateLimit, "updateRateLimit");
1125
- async function checkDailyLimit(userId, numImages = 1) {
1167
+ async function checkDailyLimit(userId, numImages = 1, updateRateLimitImmediately = true) {
1126
1168
  if (isAdmin(userId)) {
1127
1169
  return { allowed: true, isAdmin: true };
1128
1170
  }
@@ -1130,6 +1172,9 @@ function apply(ctx, config) {
1130
1172
  if (!rateLimitCheck.allowed) {
1131
1173
  return { ...rateLimitCheck, isAdmin: false };
1132
1174
  }
1175
+ if (updateRateLimitImmediately) {
1176
+ updateRateLimit(userId);
1177
+ }
1133
1178
  const usersData = await loadUsersData();
1134
1179
  const userData = usersData[userId];
1135
1180
  if (!userData) {
@@ -1309,7 +1354,6 @@ function apply(ctx, config) {
1309
1354
  const userId = session.userId;
1310
1355
  const userName = session.username || session.userId || "未知用户";
1311
1356
  if (!userId) return;
1312
- updateRateLimit(userId);
1313
1357
  const { userData, consumptionType, freeUsed, purchasedUsed } = await updateUserData(userId, userName, commandName, numImages);
1314
1358
  if (isAdmin(userId)) {
1315
1359
  await session.send(`📊 使用统计 [管理员]
@@ -1455,8 +1499,10 @@ function apply(ctx, config) {
1455
1499
  ]).catch((error) => {
1456
1500
  const userId = session.userId;
1457
1501
  if (userId) activeTasks.delete(userId);
1458
- logger.error("图像处理超时或失败", { userId, error });
1459
- return error.message === "命令执行超时" ? "图像处理超时,请重试" : `图像处理失败:${error.message}`;
1502
+ const sanitizedError = sanitizeError(error);
1503
+ logger.error("图像处理超时或失败", { userId, error: sanitizedError });
1504
+ const safeMessage = typeof error?.message === "string" ? sanitizeString(error.message) : "未知错误";
1505
+ return error.message === "命令执行超时" ? "图像处理超时,请重试" : `图像处理失败:${safeMessage}`;
1460
1506
  });
1461
1507
  }
1462
1508
  __name(processImageWithTimeout, "processImageWithTimeout");
@@ -1541,9 +1587,11 @@ ${infoParts.join("\n")}`;
1541
1587
  activeTasks.delete(userId);
1542
1588
  } catch (error) {
1543
1589
  activeTasks.delete(userId);
1544
- logger.error("图像处理失败", { userId, error });
1590
+ const sanitizedError = sanitizeError(error);
1591
+ logger.error("图像处理失败", { userId, error: sanitizedError });
1545
1592
  if (error?.message) {
1546
- return `图像处理失败:${error.message}`;
1593
+ const safeMessage = sanitizeString(error.message);
1594
+ return `图像处理失败:${safeMessage}`;
1547
1595
  }
1548
1596
  return "图像处理失败,请稍后重试";
1549
1597
  }
@@ -1705,9 +1753,11 @@ Prompt: ${prompt}`);
1705
1753
  activeTasks.delete(userId);
1706
1754
  } catch (error) {
1707
1755
  activeTasks.delete(userId);
1708
- logger.error("图片合成失败", { userId, error });
1756
+ const sanitizedError = sanitizeError(error);
1757
+ logger.error("图片合成失败", { userId, error: sanitizedError });
1709
1758
  if (error?.message) {
1710
- return `图片合成失败:${error.message}`;
1759
+ const safeMessage = sanitizeString(error.message);
1760
+ return `图片合成失败:${safeMessage}`;
1711
1761
  }
1712
1762
  return "图片合成失败,请稍后重试";
1713
1763
  }
@@ -1718,8 +1768,10 @@ Prompt: ${prompt}`);
1718
1768
  ]).catch((error) => {
1719
1769
  const userId = session.userId;
1720
1770
  if (userId) activeTasks.delete(userId);
1721
- logger.error("图片合成超时或失败", { userId, error });
1722
- return error.message === "命令执行超时" ? "图片合成超时,请重试" : `图片合成失败:${error.message}`;
1771
+ const sanitizedError = sanitizeError(error);
1772
+ logger.error("图片合成超时或失败", { userId, error: sanitizedError });
1773
+ const safeMessage = typeof error?.message === "string" ? sanitizeString(error.message) : "未知错误";
1774
+ return error.message === "命令执行超时" ? "图片合成超时,请重试" : `图片合成失败:${safeMessage}`;
1723
1775
  });
1724
1776
  });
1725
1777
  ctx.command(`${COMMANDS.RECHARGE} [content:text]`, "为用户充值次数(仅管理员)").action(async ({ session }, content) => {
@@ -14,3 +14,11 @@ export interface ProviderConfig {
14
14
  logger: any;
15
15
  ctx: any;
16
16
  }
17
+ /**
18
+ * 清理对象中的敏感信息(API KEY、密钥等)
19
+ */
20
+ export declare function sanitizeError(error: any): any;
21
+ /**
22
+ * 清理字符串中的 API KEY 模式
23
+ */
24
+ export declare function sanitizeString(str: string): string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-aka-ai-generator",
3
3
  "description": "自用AI生成插件(GPTGod & Yunwu)",
4
- "version": "0.4.2",
4
+ "version": "0.4.4",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -9,11 +9,19 @@
9
9
  "dist"
10
10
  ],
11
11
  "license": "MIT",
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsc --watch"
15
+ },
12
16
  "keywords": [
13
17
  "chatbot",
14
18
  "koishi",
15
19
  "plugin"
16
20
  ],
21
+ "devDependencies": {
22
+ "@types/node": "^20.0.0",
23
+ "typescript": "^5.0.0"
24
+ },
17
25
  "peerDependencies": {
18
26
  "koishi": "^4.18.9"
19
27
  }