koishi-plugin-onebot-verifier 1.2.0 → 1.2.2

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.
Files changed (2) hide show
  1. package/lib/index.js +32 -42
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -88,7 +88,7 @@ var Config = import_koishi.Schema.intersect([
88
88
  }).description("加群请求配置"),
89
89
  import_koishi.Schema.object({
90
90
  voteInSitu: import_koishi.Schema.boolean().description("[投票]原群投票模式").default(true),
91
- voteRatio: import_koishi.Schema.string().description("[投票]支持/反对人数").default("3:2"),
91
+ voteRatio: import_koishi.Schema.string().description("[投票]支持/反对人数").default("5:1"),
92
92
  captchaDiff: import_koishi.Schema.union([
93
93
  import_koishi.Schema.const("simple").description("简单"),
94
94
  import_koishi.Schema.const("medium").description("中等"),
@@ -101,8 +101,7 @@ function apply(ctx, config) {
101
101
  const activeTasks = /* @__PURE__ */ new Map();
102
102
  const activeCaptchas = /* @__PURE__ */ new Map();
103
103
  const inviterMap = /* @__PURE__ */ new Map();
104
- const requestMap = /* @__PURE__ */ new Map();
105
- const recentRemovals = /* @__PURE__ */ new Map();
104
+ const historyMap = /* @__PURE__ */ new Map();
106
105
  const getComment = /* @__PURE__ */ __name((comment) => {
107
106
  if (!comment) return "";
108
107
  const lines = comment.split(/[\r\n]+/).map((s) => s.trim());
@@ -134,7 +133,7 @@ function apply(ctx, config) {
134
133
  return false;
135
134
  }
136
135
  }, "executeAction");
137
- const sendNotice = /* @__PURE__ */ __name(async (session, kind, status = "waiting", overrideTarget) => {
136
+ const sendNotice = /* @__PURE__ */ __name(async (session, kind, status = "waiting", overrideTarget, specialMode) => {
138
137
  const notifyConfig = overrideTarget || config.notifyTarget || "";
139
138
  const [targetType, targetId] = notifyConfig.split(":");
140
139
  if (!targetId || !session.bot) return [];
@@ -153,7 +152,10 @@ function apply(ctx, config) {
153
152
  if (adminId) infoLines.push(`管理:${adminInfo?.name ? `${adminInfo.name}(${adminId})` : adminId}`);
154
153
  if (session.guildId) infoLines.push(`群组:${groupInfo?.name ? `${groupInfo.name}(${session.guildId})` : session.guildId}`);
155
154
  if (eventData.comment) infoLines.push(`验证信息:${eventData.comment}`);
156
- if (status === "waiting" && kind !== "removed") infoLines.push(`回复"y/n"以同意/拒绝该请求`);
155
+ if (status === "waiting" && kind !== "removed") {
156
+ if (specialMode === "vote") infoLines.push(`[投票模式]需${config.voteRatio.split(":")[0]}人同意或${config.voteRatio.split(":")[1]}人拒绝`);
157
+ infoLines.push(`使用"y/n"回复本消息以处理该请求`);
158
+ }
157
159
  const content = infoLines.join("\n");
158
160
  const msgIds = await (targetType === "private" ? session.bot.sendPrivateMessage(targetId, content) : session.bot.sendMessage(targetId, content)) || [];
159
161
  return msgIds;
@@ -166,7 +168,7 @@ function apply(ctx, config) {
166
168
  const timeoutCfg = kind === "member" ? config.memberTimeout : config.friendTimeout;
167
169
  let targetStr = config.notifyTarget || "";
168
170
  if (useInSitu && kind === "member" && session.guildId) targetStr = `guild:${session.guildId}`;
169
- const msgIds = await sendNotice(session, kind, "waiting", targetStr);
171
+ const msgIds = await sendNotice(session, kind, "waiting", targetStr, specialMode);
170
172
  if (!msgIds?.length) return;
171
173
  const task = { session, kind, messages: msgIds, specialMode, inSitu: useInSitu };
172
174
  if (specialMode === "vote") {
@@ -212,7 +214,7 @@ function apply(ctx, config) {
212
214
  }
213
215
  const verifyText = getComment(eventData.comment);
214
216
  if (kind === "member") {
215
- const rules = config.verifyRules?.filter((r) => String(r.guildId) === String(session.guildId)) || [];
217
+ const rules = config.verifyRules?.filter((r) => r.guildId === session.guildId) || [];
216
218
  for (const rule of rules) {
217
219
  const stats = (rule.minLevel ?? 0) > 0 && session.onebot && session.userId ? await session.onebot.getStrangerInfo(session.userId, true).catch(() => ({})) : null;
218
220
  const levelMatch = (stats?.qqLevel ?? 0) >= (rule.minLevel ?? 0);
@@ -222,12 +224,9 @@ function apply(ctx, config) {
222
224
  if (rule.keyword) logger.info(`[加群请求] ${session.userId} 内容 "${verifyText}" ${keywordMatch ? "=" : "≠"} "${rule.keyword}"`);
223
225
  }
224
226
  if (levelMatch && keywordMatch) {
225
- const historyKey = `${session.userId}:${session.guildId}`;
226
- const lastTime = requestMap.get(historyKey) || 0;
227
- const now = Date.now();
228
- const isFrequent = rule.frequency && now - lastTime < rule.frequency * 6e4;
227
+ const lastLeaveTime = historyMap.get(`${session.userId}:${session.guildId}`) || 0;
228
+ const isFrequent = rule.frequency && Date.now() - lastLeaveTime < rule.frequency * 6e4;
229
229
  if (isFrequent) {
230
- requestMap.set(historyKey, now);
231
230
  if (config.frequencyMode === "reject") {
232
231
  await executeAction(session, kind, false, "频繁申请,自动拒绝");
233
232
  await sendNotice(session, kind, "auto_reject");
@@ -238,7 +237,6 @@ function apply(ctx, config) {
238
237
  return await setupManual(session, kind, void 0, false, rule.action === "accept");
239
238
  }
240
239
  }
241
- requestMap.set(historyKey, now);
242
240
  if (rule.action) {
243
241
  await executeAction(session, kind, rule.action === "accept", rule.action === "accept" ? "" : "错误回答,自动拒绝");
244
242
  await sendNotice(session, kind, rule.action === "accept" ? "auto_pass" : "auto_reject");
@@ -246,7 +244,7 @@ function apply(ctx, config) {
246
244
  }
247
245
  }
248
246
  }
249
- const specialRule = config.specialRules?.find((r) => String(r.guildId) === String(session.guildId));
247
+ const specialRule = config.specialRules?.find((r) => r.guildId === session.guildId);
250
248
  if (specialRule) {
251
249
  if (specialRule.mode === "vote") return await setupManual(session, kind, "vote", config.voteInSitu);
252
250
  if (specialRule.mode === "captcha") {
@@ -329,17 +327,20 @@ function apply(ctx, config) {
329
327
  if (task.timer) clearTimeout(task.timer);
330
328
  task.messages.forEach((msg) => activeTasks.delete(msg));
331
329
  const isSuccess = await executeAction(task.session, task.kind, finalVerdict, finalVerdict ? "" : extraInfo);
332
- const replyText = isSuccess ? `已${finalVerdict ? "通过" : "拒绝"}该投票` : `处理投票失败`;
333
- await session.send(replyText).catch(() => {
330
+ if (!task.inSitu) await session.send(isSuccess ? `已${finalVerdict ? "通过" : "拒绝"}该投票` : `处理投票失败`).catch(() => {
334
331
  });
335
332
  }, "handleSpecialVote");
336
333
  ctx.on("friend-request", hookEvent("friend"));
337
334
  ctx.on("guild-request", hookEvent("guild"));
338
335
  ctx.on("guild-member-request", hookEvent("member"));
339
336
  ctx.on("guild-added", hookEvent("guild"));
337
+ ctx.on("guild-member-removed", async (session) => {
338
+ if (!session.guildId || !session.userId) return;
339
+ if (config.verifyRules?.some((r) => r.guildId === session.guildId)) historyMap.set(`${session.userId}:${session.guildId}`, Date.now());
340
+ });
340
341
  ctx.on("guild-member-added", async (session) => {
341
342
  if (!config.specialRules || !session.guildId || !session.userId) return;
342
- const rule = config.specialRules.find((r) => String(r.guildId) === String(session.guildId));
343
+ const rule = config.specialRules.find((r) => r.guildId === session.guildId);
343
344
  if (rule?.mode === "captcha") {
344
345
  let a, b, op = "+", answer;
345
346
  if (config.captchaDiff === "simple") {
@@ -364,24 +365,23 @@ function apply(ctx, config) {
364
365
  op = "×";
365
366
  answer = (a * b).toString();
366
367
  }
367
- const captchaKey = `${session.guildId}:${session.userId}`;
368
368
  await session.send(`<at id="${session.userId}"/> 请在 60 秒内回复计算结果,以进行验证:${a} ${op} ${b} =`);
369
369
  const timer = setTimeout(async () => {
370
- if (activeCaptchas.has(captchaKey)) {
371
- activeCaptchas.delete(captchaKey);
370
+ if (activeCaptchas.has(`${session.userId}:${session.guildId}`)) {
371
+ activeCaptchas.delete(`${session.userId}:${session.guildId}`);
372
372
  await session.send(`<at id="${session.userId}"/> 验证失败,将被移出本群。`);
373
373
  await session.onebot?.setGroupKick(session.guildId, session.userId, false);
374
374
  }
375
375
  }, 6e4);
376
- activeCaptchas.set(captchaKey, { guildId: session.guildId, userId: session.userId, answer, timer });
376
+ activeCaptchas.set(`${session.userId}:${session.guildId}`, { guildId: session.guildId, userId: session.userId, answer, timer });
377
377
  }
378
378
  });
379
379
  ctx.on("guild-removed", async (session) => {
380
380
  if (session.guildId) {
381
381
  const eventData = session.event?._data || {};
382
382
  const curTime = eventData.time || 0;
383
- if (Math.abs(curTime - (recentRemovals.get(session.guildId) || 0)) < 300) return;
384
- recentRemovals.set(session.guildId, curTime);
383
+ if (Math.abs(curTime - (historyMap.get(session.guildId) || 0)) < 300) return;
384
+ historyMap.set(session.guildId, curTime);
385
385
  if (config.debugMode) logger.info(`[事件] 退出: ${session.guildId} 数据: ${JSON.stringify(eventData)}`);
386
386
  if (eventData.sub_type === "kick_me") {
387
387
  const inviterId = inviterMap.get(session.guildId);
@@ -407,40 +407,30 @@ function apply(ctx, config) {
407
407
  ctx.middleware(async (session, next) => {
408
408
  if (typeof session.content !== "string") return next();
409
409
  if (session.guildId && session.userId) {
410
- const captchaKey = `${session.guildId}:${session.userId}`;
411
- const captcha = activeCaptchas.get(captchaKey);
412
- if (captcha) {
413
- const input2 = session.content.trim();
414
- if (input2 === captcha.answer) {
415
- clearTimeout(captcha.timer);
416
- activeCaptchas.delete(captchaKey);
417
- await session.send(`<at id="${session.userId}"/> 验证成功,欢迎加入本群!`);
418
- return;
419
- }
410
+ const captcha = activeCaptchas.get(`${session.userId}:${session.guildId}`);
411
+ if (captcha && session.content.trim() === captcha.answer) {
412
+ clearTimeout(captcha.timer);
413
+ activeCaptchas.delete(`${session.userId}:${session.guildId}`);
414
+ await session.send(`<at id="${session.userId}"/> 验证成功,欢迎加入本群!`);
415
+ return;
420
416
  }
421
417
  }
422
418
  if (!session.quote?.id) return next();
423
419
  const task = activeTasks.get(session.quote.id);
424
420
  if (!task) return next();
425
421
  const [ntType, ntId] = (config.notifyTarget || "").split(":");
426
- const isGlobalNotifyTarget = ntType === "private" ? session.userId === ntId : session.guildId === ntId;
427
- const isInSituGuild = task.inSitu && session.guildId && session.guildId === task.session.guildId;
428
- if (!isGlobalNotifyTarget && !isInSituGuild) return next();
422
+ if ((ntType === "private" ? session.userId !== ntId : session.guildId !== ntId) && !(task.inSitu && session.guildId === task.session.guildId)) return next();
429
423
  const input = session.content.replace(/<(quote|at)\s+[^>]*\/>/gi, "").trim();
430
424
  const cmdMatch = input.match(/^(y|n|通过|拒绝)(?:\s+(.*))?$/i);
431
425
  if (!cmdMatch) return next();
432
426
  const isApprove = ["y", "通过"].includes(cmdMatch[1].toLowerCase());
433
427
  const extraInfo = cmdMatch[2]?.trim() || "";
434
428
  if (config.debugMode) logger.info(`[操作] 收到指令: ${isApprove ? "同意" : "拒绝"}`);
435
- if (task.specialMode === "vote") {
436
- await handleSpecialVote(session, task, isApprove, extraInfo);
437
- return;
438
- }
429
+ if (task.specialMode === "vote") return await handleSpecialVote(session, task, isApprove, extraInfo);
439
430
  if (task.timer) clearTimeout(task.timer);
440
431
  task.messages.forEach((msg) => activeTasks.delete(msg));
441
432
  const isSuccess = await executeAction(task.session, task.kind, isApprove, isApprove ? "" : extraInfo, isApprove && task.kind === "friend" ? extraInfo : "");
442
- const replyText = isSuccess ? `已${isApprove ? "通过" : "拒绝"}该请求` : `处理请求失败`;
443
- await session.send(replyText).catch(() => {
433
+ await session.send(isSuccess ? `已${isApprove ? "通过" : "拒绝"}该请求` : `处理请求失败`).catch(() => {
444
434
  });
445
435
  });
446
436
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-onebot-verifier",
3
3
  "description": "[仅支持 Onebot 平台]支持好友申请/群组邀请/加群请求等的自动审核,可根据等级与正则进行筛选,并有入群验证码、投票表决、被踢清理等功能。",
4
- "version": "1.2.0",
4
+ "version": "1.2.2",
5
5
  "contributors": [
6
6
  "Yis_Rime <yis_rime@outlook.com>"
7
7
  ],