koishi-plugin-onebot-verifier 1.1.1 → 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,92 +192,69 @@ 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
  }
236
- if (config.verifyMode && config.verifyMode !== "manual") {
237
- const isApprove = config.verifyMode === "accept";
238
- await executeAction(session, kind, isApprove, "默认规则,自动处理");
239
- await sendNotice(session, kind, isApprove ? "auto_pass" : "auto_reject");
240
- return;
241
- }
242
224
  return await setupManual(session, kind);
243
225
  }
244
226
  let verdict = false;
245
227
  if (kind === "friend") {
246
- if (config.friendRegex) {
247
- const isRegexMatched = new RegExp(config.friendRegex, "i").test(verifyText);
248
- if (config.debugMode) logger.info(`[好友验证] 内容 "${verifyText}" ${isRegexMatched ? "匹配" : "不匹配"}正则 "${config.friendRegex}" `);
249
- 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}"`);
250
233
  }
251
- if (verdict !== true) {
252
- const fLevel = config.friendLevel ?? 0;
253
- if (fLevel > 0 && session.onebot && session.userId) {
254
- const stats = await session.onebot.getStrangerInfo(session.userId, true).catch(() => ({}));
255
- const isLevelMatched = (stats.qqLevel ?? 0) >= fLevel;
256
- if (config.debugMode) logger.info(`[好友验证] 用户 ${session.userId} 等级 ${stats.qqLevel ?? 0}${isLevelMatched ? ">" : "<"}${fLevel}`);
257
- if (isLevelMatched) verdict = true;
258
- }
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}"`);
259
237
  }
238
+ verdict = levelPass && regexPass;
260
239
  } else if (kind === "guild") {
261
240
  if (ctx.database && session.userId) {
262
- const userData = await ctx.database.getUser(session.platform, session.userId, ["authority"]).catch(() => null);
263
- if (userData && userData.authority > 3) {
264
- 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`);
265
244
  verdict = true;
266
245
  }
267
246
  }
268
247
  if (verdict !== true && session.onebot && session.guildId) {
269
248
  const stats = await session.onebot.getGroupInfo(session.guildId, true).catch(() => ({}));
270
- const minM = config.minMembers ?? 0;
271
- const maxC = config.maxCapacity ?? 0;
272
- if (minM > 0 && (stats.member_count ?? 0) < minM) {
273
- verdict = `群成员不足 ${minM} 人`;
274
- if (config.debugMode) logger.info(`[群组邀请] 群组 ${session.guildId} 成员数 ${stats.member_count ?? 0}<${minM}`);
275
- } else if (maxC > 0 && (stats.max_member_count ?? 0) < maxC) {
276
- verdict = `群容量不足 ${maxC} 人`;
277
- if (config.debugMode) logger.info(`[群组邀请] 群组 ${session.guildId} 受邀容量 ${stats.max_member_count ?? 0}<${maxC}`);
278
- } else {
279
- verdict = minM > 0 || maxC > 0;
280
- 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}"`);
281
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;
282
258
  }
283
259
  }
284
260
  if (verdict === true) {
@@ -316,6 +292,7 @@ function apply(ctx, config = {}) {
316
292
  finalVerdict = false;
317
293
  }
318
294
  if (!thresholdMet) return;
295
+ if (task.timer) clearTimeout(task.timer);
319
296
  task.messages.forEach((msg) => activeTasks.delete(msg));
320
297
  const isSuccess = await executeAction(task.session, task.kind, finalVerdict, finalVerdict ? "" : extraInfo);
321
298
  const replyText = isSuccess ? `已${finalVerdict ? "通过" : "拒绝"}该投票` : `处理投票失败`;
@@ -366,19 +343,19 @@ function apply(ctx, config = {}) {
366
343
  }
367
344
  });
368
345
  ctx.on("guild-removed", async (session) => {
369
- if (session.event?._data?.sub_type === "kick_me") {
370
- const gid = session.guildId;
371
- if (gid) {
372
- 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);
373
349
  if (inviterId) {
374
350
  await session.onebot?.deleteFriend(inviterId).catch(() => {
375
351
  });
376
- inviterMap.delete(gid);
352
+ inviterMap.delete(session.guildId);
377
353
  if (config.debugMode) logger.info(`[操作] 删除好友: ${inviterId}`);
378
354
  }
379
- await session.execute(`analyse.clear -g ${gid}`).catch(() => {
380
- });
381
355
  }
356
+ await session.execute(`analyse.clear -g ${session.guildId}`).catch(() => {
357
+ });
358
+ if (config.debugMode) logger.info(`[操作] 清理群组数据: ${session.guildId}`);
382
359
  }
383
360
  await sendNotice(session, "removed");
384
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.1",
4
+ "version": "1.1.3",
5
5
  "contributors": [
6
6
  "Yis_Rime <yis_rime@outlook.com>"
7
7
  ],