koishi-plugin-onebot-verifier 1.0.10 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -21,12 +21,14 @@ export interface Config {
21
21
  minLevel?: number;
22
22
  action?: 'accept' | 'reject';
23
23
  }[];
24
- voteRatio?: string;
25
24
  syncNotify?: boolean;
26
25
  specialRules?: {
27
26
  guildId: string;
28
- mode: 'vote';
27
+ enabled: boolean;
28
+ mode: 'vote' | 'captcha';
29
29
  }[];
30
+ captchaDiff?: 'simple' | 'medium' | 'hard';
31
+ voteRatio?: string;
30
32
  }
31
33
  export declare const Config: Schema<Config>;
32
34
  export declare function apply(ctx: Context, config?: Config): void;
package/lib/index.js CHANGED
@@ -73,22 +73,30 @@ var Config = import_koishi.Schema.intersect([
73
73
  import_koishi.Schema.const("accept").description("同意"),
74
74
  import_koishi.Schema.const("reject").description("拒绝")
75
75
  ]).description("操作")
76
- })).description("加群验证配置").role("table")
76
+ })).description("普通验证配置").role("table")
77
77
  }).description("加群请求配置"),
78
78
  import_koishi.Schema.object({
79
79
  syncNotify: import_koishi.Schema.boolean().description("同步通知目标").default(true),
80
80
  specialRules: import_koishi.Schema.array(import_koishi.Schema.object({
81
81
  guildId: import_koishi.Schema.string().description("群号").required(),
82
82
  mode: import_koishi.Schema.union([
83
- import_koishi.Schema.const("vote").description("投票")
84
- ]).description("模式").default("vote")
85
- })).description("群组特殊配置").role("table"),
86
- voteRatio: import_koishi.Schema.string().description("投票比例").default("3:2")
83
+ import_koishi.Schema.const("vote").description("投票"),
84
+ import_koishi.Schema.const("captcha").description("验证码")
85
+ ]).description("模式").default("vote"),
86
+ enabled: import_koishi.Schema.boolean().description("前置规则").default(true)
87
+ })).description("配置列表").role("table"),
88
+ voteRatio: import_koishi.Schema.string().description("[投票]人数").default("3:2"),
89
+ captchaDiff: import_koishi.Schema.union([
90
+ import_koishi.Schema.const("simple").description("简单"),
91
+ import_koishi.Schema.const("medium").description("中等"),
92
+ import_koishi.Schema.const("hard").description("困难")
93
+ ]).description("[验证码]难度").default("simple")
87
94
  }).description("特殊验证配置")
88
95
  ]);
89
96
  function apply(ctx, config = {}) {
90
97
  const logger = new import_koishi.Logger("onebot-verifier");
91
98
  const activeTasks = /* @__PURE__ */ new Map();
99
+ const activeCaptchas = /* @__PURE__ */ new Map();
92
100
  const inviterMap = /* @__PURE__ */ new Map();
93
101
  const getComment = /* @__PURE__ */ __name((comment) => {
94
102
  if (!comment) return "";
@@ -149,24 +157,6 @@ function apply(ctx, config = {}) {
149
157
  return [];
150
158
  }
151
159
  }, "sendNotice");
152
- const handleSpecialRule = /* @__PURE__ */ __name(async (session, kind) => {
153
- if (kind !== "member" || !config.specialRules || config.specialRules.length === 0) return false;
154
- const rule = config.specialRules.find((r) => String(r.guildId) === String(session.guildId));
155
- if (!rule) return false;
156
- if (rule.mode === "vote") {
157
- const [yesStr, noStr] = config.voteRatio.split(":");
158
- const targetYes = parseInt(yesStr) || 0;
159
- const targetNo = parseInt(noStr) || 0;
160
- let msgIds = [];
161
- if (config.syncNotify !== false) msgIds = await sendNotice(session, kind, "waiting");
162
- if (msgIds.length > 0) {
163
- const task = { session, kind, messages: msgIds, specialMode: "vote", voteTarget: { yes: targetYes, no: targetNo }, votes: { yes: /* @__PURE__ */ new Set(), no: /* @__PURE__ */ new Set() } };
164
- msgIds.forEach((id) => activeTasks.set(id, task));
165
- }
166
- return true;
167
- }
168
- return false;
169
- }, "handleSpecialRule");
170
160
  const setupManual = /* @__PURE__ */ __name(async (session, kind) => {
171
161
  const waitMinutes = config.timeout ?? 0;
172
162
  const action = kind === "member" ? config.verifyMode : config.timeoutAction;
@@ -206,7 +196,6 @@ function apply(ctx, config = {}) {
206
196
  if (config.debugMode) logger.info(`[收到请求] 类型: ${kind} 数据: ${JSON.stringify(session.event?._data || {})}`);
207
197
  const verifyText = getComment(session.event?._data?.comment);
208
198
  if (kind === "member") {
209
- if (await handleSpecialRule(session, kind)) return;
210
199
  const rules = config.verifyRules?.filter((r) => String(r.guildId) === String(session.guildId)) || [];
211
200
  for (const rule of rules) {
212
201
  const minL = rule.minLevel ?? 0;
@@ -224,9 +213,29 @@ function apply(ctx, config = {}) {
224
213
  return;
225
214
  }
226
215
  }
216
+ const specialRule = config.specialRules?.find((r) => String(r.guildId) === String(session.guildId) && r.enabled);
217
+ if (specialRule) {
218
+ if (specialRule.mode === "vote") {
219
+ const [yesStr, noStr] = config.voteRatio.split(":");
220
+ const targetYes = parseInt(yesStr) || 0;
221
+ const targetNo = parseInt(noStr) || 0;
222
+ let msgIds = [];
223
+ if (config.syncNotify !== false) msgIds = await sendNotice(session, kind, "waiting");
224
+ if (msgIds.length > 0) {
225
+ const task = { session, kind, messages: msgIds, specialMode: "vote", voteTarget: { yes: targetYes, no: targetNo }, votes: { yes: /* @__PURE__ */ new Set(), no: /* @__PURE__ */ new Set() } };
226
+ msgIds.forEach((id) => activeTasks.set(id, task));
227
+ }
228
+ return;
229
+ }
230
+ if (specialRule.mode === "captcha") {
231
+ await executeAction(session, kind, true, "验证码验证,自动通过");
232
+ if (config.syncNotify !== false) await sendNotice(session, kind, "auto_pass");
233
+ return;
234
+ }
235
+ }
227
236
  if (config.verifyMode && config.verifyMode !== "manual") {
228
237
  const isApprove = config.verifyMode === "accept";
229
- await executeAction(session, kind, isApprove, "等待超时,自动处理");
238
+ await executeAction(session, kind, isApprove, "默认规则,自动处理");
230
239
  await sendNotice(session, kind, isApprove ? "auto_pass" : "auto_reject");
231
240
  return;
232
241
  }
@@ -317,6 +326,45 @@ function apply(ctx, config = {}) {
317
326
  ctx.on("guild-request", hookEvent("guild"));
318
327
  ctx.on("guild-member-request", hookEvent("member"));
319
328
  ctx.on("guild-added", hookEvent("guild"));
329
+ ctx.on("guild-member-added", async (session) => {
330
+ if (!config.specialRules || !session.guildId || !session.userId) return;
331
+ const rule = config.specialRules.find((r) => String(r.guildId) === String(session.guildId) && r.enabled);
332
+ if (rule?.mode === "captcha") {
333
+ let a, b, op = "+", answer;
334
+ if (config.captchaDiff === "simple") {
335
+ a = Math.floor(Math.random() * 80) + 10;
336
+ b = Math.floor(Math.random() * 80) + 10;
337
+ if (Math.random() > 0.5) {
338
+ op = "+";
339
+ answer = (a + b).toString();
340
+ } else {
341
+ op = "-";
342
+ if (a < b) [a, b] = [b, a];
343
+ answer = (a - b).toString();
344
+ }
345
+ } else if (config.captchaDiff === "medium") {
346
+ a = Math.floor(Math.random() * 89) + 11;
347
+ b = Math.floor(Math.random() * 8) + 2;
348
+ op = "×";
349
+ answer = (a * b).toString();
350
+ } else {
351
+ a = Math.floor(Math.random() * 40) + 11;
352
+ b = Math.floor(Math.random() * 10) + 11;
353
+ op = "×";
354
+ answer = (a * b).toString();
355
+ }
356
+ const captchaKey = `${session.guildId}:${session.userId}`;
357
+ await session.send(`<at id="${session.userId}"/> 请在 60 秒内回复计算结果,以进行验证:${a} ${op} ${b} =`);
358
+ const timer = setTimeout(async () => {
359
+ if (activeCaptchas.has(captchaKey)) {
360
+ activeCaptchas.delete(captchaKey);
361
+ await session.send(`<at id="${session.userId}"/> 验证失败,将被移出本群。`);
362
+ await session.onebot?.setGroupKick(session.guildId, session.userId, false);
363
+ }
364
+ }, 6e4);
365
+ activeCaptchas.set(captchaKey, { guildId: session.guildId, userId: session.userId, answer, timer });
366
+ }
367
+ });
320
368
  ctx.on("guild-removed", async (session) => {
321
369
  if (session.event?._data?.sub_type === "kick_me") {
322
370
  const gid = session.guildId;
@@ -335,7 +383,21 @@ function apply(ctx, config = {}) {
335
383
  await sendNotice(session, "removed");
336
384
  });
337
385
  ctx.middleware(async (session, next) => {
338
- if (typeof session.content !== "string" || !session.quote?.id) return next();
386
+ if (typeof session.content !== "string") return next();
387
+ if (session.guildId && session.userId) {
388
+ const captchaKey = `${session.guildId}:${session.userId}`;
389
+ const captcha = activeCaptchas.get(captchaKey);
390
+ if (captcha) {
391
+ const input2 = session.content.trim();
392
+ if (input2 === captcha.answer) {
393
+ clearTimeout(captcha.timer);
394
+ activeCaptchas.delete(captchaKey);
395
+ await session.send(`<at id="${session.userId}"/> 验证成功,欢迎加入本群!`);
396
+ return;
397
+ }
398
+ }
399
+ }
400
+ if (!session.quote?.id) return next();
339
401
  const task = activeTasks.get(session.quote.id);
340
402
  if (!task) return next();
341
403
  const [targetType, targetId] = (config.notifyTarget || "").split(":");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-onebot-verifier",
3
3
  "description": "适用于 Onebot 的审核插件,支持自动审核好友/加群/邀请请求",
4
- "version": "1.0.10",
4
+ "version": "1.1.1",
5
5
  "contributors": [
6
6
  "Yis_Rime <yis_rime@outlook.com>"
7
7
  ],