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.
- package/lib/index.js +32 -42
- 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("
|
|
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
|
|
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")
|
|
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) =>
|
|
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
|
|
226
|
-
const
|
|
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) =>
|
|
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
|
-
|
|
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) =>
|
|
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(
|
|
371
|
-
activeCaptchas.delete(
|
|
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(
|
|
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 - (
|
|
384
|
-
|
|
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
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
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
|
-
|
|
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
|
-
|
|
443
|
-
await session.send(replyText).catch(() => {
|
|
433
|
+
await session.send(isSuccess ? `已${isApprove ? "通过" : "拒绝"}该请求` : `处理请求失败`).catch(() => {
|
|
444
434
|
});
|
|
445
435
|
});
|
|
446
436
|
}
|
package/package.json
CHANGED