koishi-plugin-spawn-modified 1.2.6 → 1.2.7

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.d.ts CHANGED
@@ -13,6 +13,7 @@ export interface Config {
13
13
  encoding?: typeof encodings[number];
14
14
  timeout?: number;
15
15
  renderImage?: boolean;
16
+ exemptUsers?: string[];
16
17
  blockedCommands?: string[];
17
18
  restrictDirectory?: boolean;
18
19
  authority?: number;
package/lib/index.js CHANGED
@@ -63,6 +63,7 @@ exports.Config = koishi_1.Schema.object({
63
63
  encoding: koishi_1.Schema.union(encodings).description('输出内容编码。').default('utf8'),
64
64
  timeout: koishi_1.Schema.number().description('最长运行时间。').default(koishi_1.Time.minute),
65
65
  renderImage: koishi_1.Schema.boolean().description('是否将命令执行结果渲染为图片(需要安装 puppeteer 插件)。').default(false),
66
+ exemptUsers: koishi_1.Schema.array(String).description('例外用户列表,格式为 "群组ID:用户ID"。私聊时群组ID为0。匹配的用户将无视一切过滤器。').default([]),
66
67
  blockedCommands: koishi_1.Schema.array(String).description('违禁命令列表(命令的开头部分)。').default([]),
67
68
  restrictDirectory: koishi_1.Schema.boolean().description('是否限制在当前目录及子目录内执行命令(禁止 cd 到上级或其他目录)。').default(false),
68
69
  authority: koishi_1.Schema.number().description('exec 命令所需权限等级。').default(4),
@@ -328,30 +329,34 @@ function apply(ctx, config) {
328
329
  ctx.i18n.define('zh-CN', require('./locales/zh-CN'));
329
330
  ctx.command('exec <command:text>', { authority: (_a = config.authority) !== null && _a !== void 0 ? _a : 4 })
330
331
  .action(function (_a, command_1) { return __awaiter(_this, [_a, command_1], void 0, function (_b, command) {
331
- var filterList, filterMode, sessionId, rootDir, currentDir, cdValidation, pathValidation, timeout, state;
332
+ var guildId, userId, userKey, isExempt, filterList, filterMode, sessionId, rootDir, currentDir, cdValidation, pathValidation, timeout, state;
332
333
  var _this = this;
333
- var _c;
334
+ var _c, _d, _e;
334
335
  var session = _b.session;
335
- return __generator(this, function (_d) {
336
- switch (_d.label) {
336
+ return __generator(this, function (_f) {
337
+ switch (_f.label) {
337
338
  case 0:
338
339
  if (!command) {
339
340
  return [2 /*return*/, session.text('.expect-text')];
340
341
  }
341
342
  command = (0, koishi_1.h)('', koishi_1.h.parse(command)).toString(true);
342
- filterList = (((_c = config.commandList) === null || _c === void 0 ? void 0 : _c.length) ? config.commandList : config.blockedCommands) || [];
343
+ guildId = session.guildId || '0';
344
+ userId = session.userId || '';
345
+ userKey = "".concat(guildId, ":").concat(userId);
346
+ isExempt = (_d = (_c = config.exemptUsers) === null || _c === void 0 ? void 0 : _c.some(function (entry) { return entry === userKey; })) !== null && _d !== void 0 ? _d : false;
347
+ filterList = (((_e = config.commandList) === null || _e === void 0 ? void 0 : _e.length) ? config.commandList : config.blockedCommands) || [];
343
348
  filterMode = config.commandFilterMode || 'blacklist';
344
- if (isCommandBlocked(command, filterMode, filterList)) {
349
+ if (!isExempt && isCommandBlocked(command, filterMode, filterList)) {
345
350
  return [2 /*return*/, session.text('.blocked-command')];
346
351
  }
347
352
  sessionId = session.uid || session.channelId;
348
353
  rootDir = path_1.default.resolve(ctx.baseDir, config.root);
349
354
  currentDir = sessionDirs.get(sessionId) || rootDir;
350
- cdValidation = validateCdCommand(command, currentDir, rootDir, config.restrictDirectory);
355
+ cdValidation = validateCdCommand(command, currentDir, rootDir, !isExempt && config.restrictDirectory);
351
356
  if (!cdValidation.valid) {
352
357
  return [2 /*return*/, session.text('.restricted-directory')];
353
358
  }
354
- pathValidation = validatePathAccess(command, currentDir, rootDir, config.restrictDirectory);
359
+ pathValidation = validatePathAccess(command, currentDir, rootDir, !isExempt && config.restrictDirectory);
355
360
  if (!pathValidation.valid) {
356
361
  return [2 /*return*/, session.text('.restricted-path')];
357
362
  }
@@ -360,8 +365,8 @@ function apply(ctx, config) {
360
365
  if (!!config.renderImage) return [3 /*break*/, 2];
361
366
  return [4 /*yield*/, session.send(session.text('.started', state))];
362
367
  case 1:
363
- _d.sent();
364
- _d.label = 2;
368
+ _f.sent();
369
+ _f.label = 2;
365
370
  case 2: return [2 /*return*/, new Promise(function (resolve) {
366
371
  var start = Date.now();
367
372
  var child = (0, child_process_1.exec)(command, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-spawn-modified",
3
- "version": "1.2.6",
3
+ "version": "1.2.7",
4
4
  "description": "Run shell commands with Koishi",
5
5
  "keywords": [
6
6
  "bot",
package/src/index.ts CHANGED
@@ -21,6 +21,7 @@ export interface Config {
21
21
  encoding?: typeof encodings[number]
22
22
  timeout?: number
23
23
  renderImage?: boolean
24
+ exemptUsers?: string[]
24
25
  blockedCommands?: string[]
25
26
  restrictDirectory?: boolean
26
27
  authority?: number
@@ -34,6 +35,7 @@ export const Config: Schema<Config> = Schema.object({
34
35
  encoding: Schema.union(encodings).description('输出内容编码。').default('utf8'),
35
36
  timeout: Schema.number().description('最长运行时间。').default(Time.minute),
36
37
  renderImage: Schema.boolean().description('是否将命令执行结果渲染为图片(需要安装 puppeteer 插件)。').default(false),
38
+ exemptUsers: Schema.array(String).description('例外用户列表,格式为 "群组ID:用户ID"。私聊时群组ID为0。匹配的用户将无视一切过滤器。').default([]),
37
39
  blockedCommands: Schema.array(String).description('违禁命令列表(命令的开头部分)。').default([]),
38
40
  restrictDirectory: Schema.boolean().description('是否限制在当前目录及子目录内执行命令(禁止 cd 到上级或其他目录)。').default(false),
39
41
  authority: Schema.number().description('exec 命令所需权限等级。').default(4),
@@ -441,21 +443,28 @@ export function apply(ctx: Context, config: Config) {
441
443
  }
442
444
 
443
445
  command = h('', h.parse(command)).toString(true)
446
+
447
+ // 检查是否为例外用户(无视一切过滤器)
448
+ const guildId = session.guildId || '0'
449
+ const userId = session.userId || ''
450
+ const userKey = `${guildId}:${userId}`
451
+ const isExempt = config.exemptUsers?.some(entry => entry === userKey) ?? false
452
+
444
453
  // 检查命令过滤(黑/白名单);仅使用配置提供的正则
445
454
  const filterList = (config.commandList?.length ? config.commandList : config.blockedCommands) || []
446
455
  const filterMode = config.commandFilterMode || 'blacklist'
447
- if (isCommandBlocked(command, filterMode, filterList)) {
456
+ if (!isExempt && isCommandBlocked(command, filterMode, filterList)) {
448
457
  return session.text('.blocked-command')
449
458
  }
450
459
  const sessionId = session.uid || session.channelId
451
460
  const rootDir = path.resolve(ctx.baseDir, config.root)
452
461
  const currentDir = sessionDirs.get(sessionId) || rootDir
453
462
  // 验证 cd 命令
454
- const cdValidation = validateCdCommand(command, currentDir, rootDir, config.restrictDirectory)
463
+ const cdValidation = validateCdCommand(command, currentDir, rootDir, !isExempt && config.restrictDirectory)
455
464
  if (!cdValidation.valid) {
456
465
  return session.text('.restricted-directory')
457
466
  }
458
- const pathValidation = validatePathAccess(command, currentDir, rootDir, config.restrictDirectory)
467
+ const pathValidation = validatePathAccess(command, currentDir, rootDir, !isExempt && config.restrictDirectory)
459
468
  if (!pathValidation.valid) {
460
469
  return session.text('.restricted-path')
461
470
  }