koishi-plugin-onebot-verifier 1.1.2 → 1.1.3

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,7 +21,6 @@ export interface Config {
21
21
  minLevel?: number;
22
22
  action?: 'accept' | 'reject';
23
23
  }[];
24
- syncNotify?: boolean;
25
24
  specialRules?: {
26
25
  guildId: string;
27
26
  enabled: boolean;
package/lib/index.js CHANGED
@@ -76,7 +76,6 @@ var Config = import_koishi.Schema.intersect([
76
76
  })).description("普通验证配置").role("table")
77
77
  }).description("加群请求配置"),
78
78
  import_koishi.Schema.object({
79
- syncNotify: import_koishi.Schema.boolean().description("同步通知目标").default(true),
80
79
  specialRules: import_koishi.Schema.array(import_koishi.Schema.object({
81
80
  guildId: import_koishi.Schema.string().description("群号").required(),
82
81
  mode: import_koishi.Schema.union([
@@ -148,7 +147,7 @@ function apply(ctx, config = {}) {
148
147
  if (adminId) infoLines.push(`管理:${adminInfo?.name ? `${adminInfo.name}(${adminId})` : adminId}`);
149
148
  if (session.guildId) infoLines.push(`群组:${groupInfo?.name ? `${groupInfo.name}(${session.guildId})` : session.guildId}`);
150
149
  if (eventData.comment) infoLines.push(`验证信息:${eventData.comment}`);
151
- if (status === "waiting") infoLines.push(`使用"y/n"回复本消息,以同意/拒绝该请求`);
150
+ if (status === "waiting" && kind !== "removed") infoLines.push(`回复"y/n"以同意/拒绝该请求`);
152
151
  const content = infoLines.join("\n");
153
152
  const msgIds = await (targetType === "private" ? session.bot.sendPrivateMessage(targetId, content) : session.bot.sendMessage(targetId, content)) || [];
154
153
  return msgIds;
@@ -157,18 +156,24 @@ function apply(ctx, config = {}) {
157
156
  return [];
158
157
  }
159
158
  }, "sendNotice");
160
- const setupManual = /* @__PURE__ */ __name(async (session, kind) => {
159
+ const setupManual = /* @__PURE__ */ __name(async (session, kind, specialMode) => {
161
160
  const waitMinutes = config.timeout ?? 0;
162
161
  const action = kind === "member" ? config.verifyMode : config.timeoutAction;
163
- if (waitMinutes > 0) {
164
- const msgIds = await sendNotice(session, kind, "waiting");
165
- if (!msgIds?.length) return;
166
- const task = { session, kind, messages: msgIds };
167
- msgIds.forEach((id) => activeTasks.set(id, task));
162
+ const msgIds = await sendNotice(session, kind, "waiting");
163
+ if (!msgIds?.length) return;
164
+ const task = { session, kind, messages: msgIds, specialMode };
165
+ if (specialMode === "vote") {
166
+ const [yesStr, noStr] = config.voteRatio.split(":");
167
+ task.voteTarget = { yes: parseInt(yesStr) || 0, no: parseInt(noStr) || 0 };
168
+ task.votes = { yes: /* @__PURE__ */ new Set(), no: /* @__PURE__ */ new Set() };
169
+ }
170
+ msgIds.forEach((id) => activeTasks.set(id, task));
171
+ if (waitMinutes > 0 && (specialMode === "vote" || action !== "manual")) {
168
172
  task.timer = setTimeout(async () => {
169
173
  if (!activeTasks.has(msgIds[0])) return;
170
174
  msgIds.forEach((id) => activeTasks.delete(id));
171
- const finalAction = kind === "member" ? config.verifyMode ?? "manual" : config.timeoutAction ?? "accept";
175
+ let finalAction = action;
176
+ if (specialMode === "vote" && finalAction === "manual") finalAction = "reject";
172
177
  if (finalAction === "manual") return;
173
178
  const isPass = finalAction === "accept";
174
179
  await executeAction(session, kind, isPass, isPass ? "" : "等待超时,自动拒绝");
@@ -180,12 +185,6 @@ function apply(ctx, config = {}) {
180
185
  }
181
186
  if (config.debugMode) logger.info(`[操作] 等待超时,默认${isPass ? "通过" : "拒绝"}`);
182
187
  }, waitMinutes * 6e4);
183
- } else {
184
- if (action === "manual" || !action) return await sendNotice(session, kind, "waiting");
185
- const isPass = action === "accept";
186
- await executeAction(session, kind, isPass, "等待超时,自动处理");
187
- await sendNotice(session, kind, isPass ? "auto_pass" : "auto_reject");
188
- if (config.debugMode) logger.info(`[操作] 无需等待,默认${isPass ? "通过" : "拒绝"}`);
189
188
  }
190
189
  }, "setupManual");
191
190
  const hookEvent = /* @__PURE__ */ __name((kind) => async (session) => {
@@ -193,43 +192,32 @@ function apply(ctx, config = {}) {
193
192
  if (eventData.user_id) session.userId = String(eventData.user_id);
194
193
  if (eventData.group_id) session.guildId = String(eventData.group_id);
195
194
  try {
196
- if (config.debugMode) logger.info(`[收到请求] 类型: ${kind} 数据: ${JSON.stringify(session.event?._data || {})}`);
197
- const verifyText = getComment(session.event?._data?.comment);
195
+ if (config.debugMode) logger.info(`[请求] 类型: ${kind} 数据: ${JSON.stringify(eventData)}`);
196
+ const verifyText = getComment(eventData.comment);
198
197
  if (kind === "member") {
199
198
  const rules = config.verifyRules?.filter((r) => String(r.guildId) === String(session.guildId)) || [];
200
199
  for (const rule of rules) {
201
- const minL = rule.minLevel ?? 0;
202
- const stats = minL > 0 && session.onebot && session.userId ? await session.onebot.getStrangerInfo(session.userId, true).catch(() => ({})) : null;
200
+ const stats = (rule.minLevel ?? 0) > 0 && session.onebot && session.userId ? await session.onebot.getStrangerInfo(session.userId, true).catch(() => ({})) : null;
201
+ const levelMatch = (stats?.qqLevel ?? 0) >= (rule.minLevel ?? 0);
203
202
  const keywordMatch = !rule.keyword || new RegExp(rule.keyword, "i").test(verifyText);
204
- const levelMatch = !stats || (stats.qqLevel ?? 0) >= minL;
205
203
  if (config.debugMode) {
206
- if (rule.keyword) logger.info(`[加群验证] 内容 "${verifyText}" ${keywordMatch ? "匹配" : "不匹配"}正则 "${rule.keyword}"`);
207
- if (stats) logger.info(`[加群验证] 用户 ${session.userId} 等级 ${stats.qqLevel ?? 0}${levelMatch ? ">" : "<"}${minL}`);
204
+ if ((rule.minLevel ?? 0) > 0) logger.info(`[加群请求] ${session.userId} 等级 ${stats?.qqLevel ?? 0} ${levelMatch ? ">" : "<"} "${rule.minLevel ?? 0}"`);
205
+ if (rule.keyword) logger.info(`[加群请求] ${session.userId} 内容 "${verifyText}" ${keywordMatch ? "=" : ""} "${rule.keyword}"`);
208
206
  }
209
- if (keywordMatch && levelMatch && rule.action) {
210
- const isApprove = rule.action === "accept";
211
- await executeAction(session, kind, isApprove, isApprove ? "" : "命中规则,自动拒绝");
212
- await sendNotice(session, kind, isApprove ? "auto_pass" : "auto_reject");
213
- return;
207
+ if (levelMatch && keywordMatch) {
208
+ if (rule.action) {
209
+ await executeAction(session, kind, rule.action === "accept", rule.action === "accept" ? "" : "命中规则,自动拒绝");
210
+ await sendNotice(session, kind, rule.action === "accept" ? "auto_pass" : "auto_reject");
211
+ return;
212
+ }
214
213
  }
215
214
  }
216
215
  const specialRule = config.specialRules?.find((r) => String(r.guildId) === String(session.guildId) && r.enabled);
217
216
  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
- }
217
+ if (specialRule.mode === "vote") return await setupManual(session, kind, "vote");
230
218
  if (specialRule.mode === "captcha") {
231
219
  await executeAction(session, kind, true, "验证码验证,自动通过");
232
- if (config.syncNotify !== false) await sendNotice(session, kind, "auto_pass");
220
+ await sendNotice(session, kind, "auto_pass");
233
221
  return;
234
222
  }
235
223
  }
@@ -237,42 +225,36 @@ function apply(ctx, config = {}) {
237
225
  }
238
226
  let verdict = false;
239
227
  if (kind === "friend") {
240
- if (config.friendRegex) {
241
- const isRegexMatched = new RegExp(config.friendRegex, "i").test(verifyText);
242
- if (config.debugMode) logger.info(`[好友验证] 内容 "${verifyText}" ${isRegexMatched ? "匹配" : "不匹配"}正则 "${config.friendRegex}" `);
243
- if (isRegexMatched) verdict = true;
228
+ let levelPass = true, regexPass = true;
229
+ if (config.friendLevel && config.friendLevel > 0 && session.onebot && session.userId) {
230
+ const stats = await session.onebot.getStrangerInfo(session.userId, true).catch(() => ({}));
231
+ levelPass = (stats.qqLevel ?? 0) >= config.friendLevel;
232
+ if (config.debugMode) logger.info(`[好友验证] ${session.userId} 等级 ${stats.qqLevel ?? 0} ${levelPass ? ">" : "<"} "${config.friendLevel}"`);
244
233
  }
245
- if (verdict !== true) {
246
- const fLevel = config.friendLevel ?? 0;
247
- if (fLevel > 0 && session.onebot && session.userId) {
248
- const stats = await session.onebot.getStrangerInfo(session.userId, true).catch(() => ({}));
249
- const isLevelMatched = (stats.qqLevel ?? 0) >= fLevel;
250
- if (config.debugMode) logger.info(`[好友验证] 用户 ${session.userId} 等级 ${stats.qqLevel ?? 0}${isLevelMatched ? ">" : "<"}${fLevel}`);
251
- if (isLevelMatched) verdict = true;
252
- }
234
+ if (config.friendRegex) {
235
+ regexPass = new RegExp(config.friendRegex, "i").test(verifyText);
236
+ if (config.debugMode) logger.info(`[好友验证] ${session.userId} 内容 "${verifyText}" ${regexPass ? "=" : "≠"} "${config.friendRegex}"`);
253
237
  }
238
+ verdict = levelPass && regexPass;
254
239
  } else if (kind === "guild") {
255
240
  if (ctx.database && session.userId) {
256
- const userData = await ctx.database.getUser(session.platform, session.userId, ["authority"]).catch(() => null);
257
- if (userData && userData.authority > 3) {
258
- if (config.debugMode) logger.info(`[群组邀请] 用户 ${session.userId} 权限 ${userData.authority}>3`);
241
+ const auth = (await ctx.database.getUser(session.platform, session.userId, ["authority"]).catch(() => null))?.authority ?? 0;
242
+ if (auth > 3) {
243
+ if (config.debugMode) logger.info(`[群组邀请] ${session.userId} 权限 ${auth} > 3`);
259
244
  verdict = true;
260
245
  }
261
246
  }
262
247
  if (verdict !== true && session.onebot && session.guildId) {
263
248
  const stats = await session.onebot.getGroupInfo(session.guildId, true).catch(() => ({}));
264
- const minM = config.minMembers ?? 0;
265
- const maxC = config.maxCapacity ?? 0;
266
- if (minM > 0 && (stats.member_count ?? 0) < minM) {
267
- verdict = `群成员不足 ${minM} 人`;
268
- if (config.debugMode) logger.info(`[群组邀请] 群组 ${session.guildId} 成员数 ${stats.member_count ?? 0}<${minM}`);
269
- } else if (maxC > 0 && (stats.max_member_count ?? 0) < maxC) {
270
- verdict = `群容量不足 ${maxC} 人`;
271
- if (config.debugMode) logger.info(`[群组邀请] 群组 ${session.guildId} 受邀容量 ${stats.max_member_count ?? 0}<${maxC}`);
272
- } else {
273
- verdict = minM > 0 || maxC > 0;
274
- if (config.debugMode && verdict) logger.info(`[群组邀请] 群组 ${session.guildId} 成员数 ${stats.member_count ?? 0}>${minM},受邀容量 ${stats.max_member_count ?? 0}>${maxC}`);
249
+ const minPass = (stats.member_count ?? 0) >= (config.minMembers ?? 0);
250
+ const maxPass = (stats.max_member_count ?? 0) >= (config.maxCapacity ?? 0);
251
+ if (config.debugMode) {
252
+ if ((config.minMembers ?? 0) > 0) logger.info(`[群组邀请] ${session.guildId} 人数 ${stats.member_count ?? 0} ${minPass ? ">" : "<"} "${config.minMembers ?? 0}"`);
253
+ if ((config.maxCapacity ?? 0) > 0) logger.info(`[群组邀请] ${session.guildId} 容量 ${stats.max_member_count ?? 0} ${maxPass ? ">" : "<"} "${config.maxCapacity ?? 0}"`);
275
254
  }
255
+ if (!minPass) verdict = `群人数不足 ${config.minMembers ?? 0} 人`;
256
+ else if (!maxPass) verdict = `群容量不足 ${config.maxCapacity ?? 0} 人`;
257
+ else verdict = (config.minMembers ?? 0) > 0 || (config.maxCapacity ?? 0) > 0;
276
258
  }
277
259
  }
278
260
  if (verdict === true) {
@@ -310,6 +292,7 @@ function apply(ctx, config = {}) {
310
292
  finalVerdict = false;
311
293
  }
312
294
  if (!thresholdMet) return;
295
+ if (task.timer) clearTimeout(task.timer);
313
296
  task.messages.forEach((msg) => activeTasks.delete(msg));
314
297
  const isSuccess = await executeAction(task.session, task.kind, finalVerdict, finalVerdict ? "" : extraInfo);
315
298
  const replyText = isSuccess ? `已${finalVerdict ? "通过" : "拒绝"}该投票` : `处理投票失败`;
@@ -360,19 +343,19 @@ function apply(ctx, config = {}) {
360
343
  }
361
344
  });
362
345
  ctx.on("guild-removed", async (session) => {
363
- if (session.event?._data?.sub_type === "kick_me") {
364
- const gid = session.guildId;
365
- if (gid) {
366
- const inviterId = inviterMap.get(gid);
346
+ if (session.guildId) {
347
+ if (session.event?._data?.sub_type === "kick_me") {
348
+ const inviterId = inviterMap.get(session.guildId);
367
349
  if (inviterId) {
368
350
  await session.onebot?.deleteFriend(inviterId).catch(() => {
369
351
  });
370
- inviterMap.delete(gid);
352
+ inviterMap.delete(session.guildId);
371
353
  if (config.debugMode) logger.info(`[操作] 删除好友: ${inviterId}`);
372
354
  }
373
- await session.execute(`analyse.clear -g ${gid}`).catch(() => {
374
- });
375
355
  }
356
+ await session.execute(`analyse.clear -g ${session.guildId}`).catch(() => {
357
+ });
358
+ if (config.debugMode) logger.info(`[操作] 清理群组数据: ${session.guildId}`);
376
359
  }
377
360
  await sendNotice(session, "removed");
378
361
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-onebot-verifier",
3
3
  "description": "适用于 Onebot 的审核插件,支持自动审核好友/加群/邀请请求",
4
- "version": "1.1.2",
4
+ "version": "1.1.3",
5
5
  "contributors": [
6
6
  "Yis_Rime <yis_rime@outlook.com>"
7
7
  ],