koishi-plugin-onebot-verifier 1.0.3 → 1.0.5
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 +2 -3
- package/lib/index.js +44 -40
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -6,7 +6,6 @@ export declare const inject: {
|
|
|
6
6
|
export declare const usage = "\n<div style=\"border-radius: 10px; border: 1px solid #ddd; padding: 16px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);\">\n <h2 style=\"margin-top: 0; color: #4a6ee0;\">\uD83D\uDCCC \u63D2\u4EF6\u8BF4\u660E</h2>\n <p>\uD83D\uDCD6 <strong>\u4F7F\u7528\u6587\u6863</strong>\uFF1A\u8BF7\u70B9\u51FB\u5DE6\u4E0A\u89D2\u7684 <strong>\u63D2\u4EF6\u4E3B\u9875</strong> \u67E5\u770B\u63D2\u4EF6\u4F7F\u7528\u6587\u6863</p>\n <p>\uD83D\uDD0D <strong>\u66F4\u591A\u63D2\u4EF6</strong>\uFF1A\u53EF\u8BBF\u95EE <a href=\"https://github.com/YisRime\" style=\"color:#4a6ee0;text-decoration:none;\">\u82E1\u6DDE\u7684 GitHub</a> \u67E5\u770B\u672C\u4EBA\u7684\u6240\u6709\u63D2\u4EF6</p>\n</div>\n<div style=\"border-radius: 10px; border: 1px solid #ddd; padding: 16px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);\">\n <h2 style=\"margin-top: 0; color: #e0574a;\">\u2764\uFE0F \u652F\u6301\u4E0E\u53CD\u9988</h2>\n <p>\uD83C\uDF1F \u559C\u6B22\u8FD9\u4E2A\u63D2\u4EF6\uFF1F\u8BF7\u5728 <a href=\"https://github.com/YisRime\" style=\"color:#e0574a;text-decoration:none;\">GitHub</a> \u4E0A\u7ED9\u6211\u4E00\u4E2A Star\uFF01</p>\n <p>\uD83D\uDC1B \u9047\u5230\u95EE\u9898\uFF1F\u8BF7\u901A\u8FC7 <strong>Issues</strong> \u63D0\u4EA4\u53CD\u9988\uFF0C\u6216\u52A0\u5165 QQ \u7FA4 <a href=\"https://qm.qq.com/q/PdLMx9Jowq\" style=\"color:#e0574a;text-decoration:none;\"><strong>855571375</strong></a> \u8FDB\u884C\u4EA4\u6D41</p>\n</div>\n";
|
|
7
7
|
export interface Config {
|
|
8
8
|
notifyTarget?: string;
|
|
9
|
-
notifyAuto?: boolean;
|
|
10
9
|
debugMode?: boolean;
|
|
11
10
|
timeout?: number;
|
|
12
11
|
timeoutAction?: 'accept' | 'reject';
|
|
@@ -14,12 +13,12 @@ export interface Config {
|
|
|
14
13
|
friendRegex?: string;
|
|
15
14
|
minMembers?: number;
|
|
16
15
|
maxCapacity?: number;
|
|
17
|
-
verifyMode?: '
|
|
16
|
+
verifyMode?: 'accept' | 'reject' | 'manual';
|
|
18
17
|
verifyRules?: {
|
|
19
18
|
guildId: string;
|
|
20
19
|
keyword?: string;
|
|
21
20
|
minLevel?: number;
|
|
22
|
-
|
|
21
|
+
action?: 'accept' | 'reject';
|
|
23
22
|
}[];
|
|
24
23
|
}
|
|
25
24
|
export declare const Config: Schema<Config>;
|
package/lib/index.js
CHANGED
|
@@ -45,7 +45,6 @@ var usage = `
|
|
|
45
45
|
var Config = import_koishi.Schema.intersect([
|
|
46
46
|
import_koishi.Schema.object({
|
|
47
47
|
notifyTarget: import_koishi.Schema.string().description("通知目标(guild/private:number)").required(),
|
|
48
|
-
notifyAuto: import_koishi.Schema.boolean().description("发送全部通知").default(true),
|
|
49
48
|
debugMode: import_koishi.Schema.boolean().description("输出调试日志").default(false)
|
|
50
49
|
}).description("基础配置"),
|
|
51
50
|
import_koishi.Schema.object({
|
|
@@ -61,15 +60,15 @@ var Config = import_koishi.Schema.intersect([
|
|
|
61
60
|
}).description("好友邀群配置"),
|
|
62
61
|
import_koishi.Schema.object({
|
|
63
62
|
verifyMode: import_koishi.Schema.union([
|
|
64
|
-
import_koishi.Schema.const("
|
|
65
|
-
import_koishi.Schema.const("
|
|
63
|
+
import_koishi.Schema.const("accept").description("同意"),
|
|
64
|
+
import_koishi.Schema.const("reject").description("拒绝"),
|
|
66
65
|
import_koishi.Schema.const("manual").description("手动")
|
|
67
|
-
]).description("处理模式").default("
|
|
66
|
+
]).description("处理模式").default("manual"),
|
|
68
67
|
verifyRules: import_koishi.Schema.array(import_koishi.Schema.object({
|
|
69
68
|
guildId: import_koishi.Schema.string().description("群号").required(),
|
|
70
69
|
keyword: import_koishi.Schema.string().description("正则"),
|
|
71
70
|
minLevel: import_koishi.Schema.number().description("等级").default(-1),
|
|
72
|
-
|
|
71
|
+
action: import_koishi.Schema.union([
|
|
73
72
|
import_koishi.Schema.const("accept").description("同意"),
|
|
74
73
|
import_koishi.Schema.const("reject").description("拒绝")
|
|
75
74
|
]).description("操作")
|
|
@@ -82,6 +81,7 @@ function apply(ctx, config = {}) {
|
|
|
82
81
|
const executeAction = /* @__PURE__ */ __name(async (session, kind, pass, reason = "", remark = "") => {
|
|
83
82
|
try {
|
|
84
83
|
const eventData = session.event?._data || {};
|
|
84
|
+
if (config.debugMode) logger.info(`[执行操作] 类型:${kind} 结果:${pass ? "同意" : "拒绝"} 原因:${reason || "无"}`);
|
|
85
85
|
if (!pass && kind === "guild" && session.guildId && (session.event?.type === "guild-added" || eventData.notice_type === "group_increase")) {
|
|
86
86
|
if (reason) {
|
|
87
87
|
try {
|
|
@@ -107,7 +107,6 @@ function apply(ctx, config = {}) {
|
|
|
107
107
|
if (!notifyConfig) return [];
|
|
108
108
|
const [targetType, targetId] = notifyConfig.split(":");
|
|
109
109
|
if (!targetId || targetType !== "guild" && targetType !== "private") return [];
|
|
110
|
-
if (status !== "waiting" && !config.notifyAuto) return [];
|
|
111
110
|
try {
|
|
112
111
|
const eventData = session.event?._data || {};
|
|
113
112
|
const userInfo = session.userId ? await session.bot.getUser?.(session.userId)?.catch(() => null) : null;
|
|
@@ -133,28 +132,18 @@ function apply(ctx, config = {}) {
|
|
|
133
132
|
const rawText = session.event?._data?.comment || "";
|
|
134
133
|
const cleanLines = rawText.split(/[\r\n]+/).map((s) => s.trim()).filter((s) => /^(回答)[::]/i.test(s)).map((s) => s.replace(/^(回答)[::]\s*/i, ""));
|
|
135
134
|
const verifyText = cleanLines.length > 0 ? cleanLines.join("\n") : rawText;
|
|
136
|
-
if (kind === "member") {
|
|
137
|
-
const groupRule = config.verifyRules?.find((r) => r.guildId === session.guildId);
|
|
138
|
-
if (!groupRule) return false;
|
|
139
|
-
try {
|
|
140
|
-
if (groupRule.keyword && !new RegExp(groupRule.keyword, "i").test(verifyText)) return false;
|
|
141
|
-
const limitLevel = groupRule.minLevel ?? -1;
|
|
142
|
-
if (limitLevel >= 0 && session.onebot && session.userId) {
|
|
143
|
-
const stats = await session.onebot.getStrangerInfo(session.userId, true);
|
|
144
|
-
if ((stats.qqLevel ?? 0) < limitLevel) return `QQ 等级低于 ${limitLevel} 级`;
|
|
145
|
-
}
|
|
146
|
-
} catch {
|
|
147
|
-
return false;
|
|
148
|
-
}
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
135
|
if (kind === "friend") {
|
|
152
136
|
try {
|
|
153
|
-
if (config.friendRegex && new RegExp(config.friendRegex, "i").test(verifyText))
|
|
137
|
+
if (config.friendRegex && new RegExp(config.friendRegex, "i").test(verifyText)) {
|
|
138
|
+
if (config.debugMode) logger.info(`[规则匹配] 好友检查: ${config.friendRegex}`);
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
154
141
|
const limitLevel = config.friendLevel ?? -1;
|
|
155
142
|
if (limitLevel >= 0 && session.onebot && session.userId) {
|
|
156
143
|
const stats = await session.onebot.getStrangerInfo(session.userId, true);
|
|
157
|
-
|
|
144
|
+
const isPassed = (stats.qqLevel ?? 0) >= limitLevel;
|
|
145
|
+
if (config.debugMode) logger.info(`[规则判定] 等级检查: ${stats.qqLevel} > ${limitLevel} = ${isPassed}`);
|
|
146
|
+
if (!isPassed) return `QQ 等级低于 ${limitLevel} 级`;
|
|
158
147
|
return true;
|
|
159
148
|
}
|
|
160
149
|
} catch {
|
|
@@ -165,14 +154,23 @@ function apply(ctx, config = {}) {
|
|
|
165
154
|
if (kind === "guild") {
|
|
166
155
|
try {
|
|
167
156
|
const userData = session.userId ? await ctx.database.getUser(session.platform, session.userId) : null;
|
|
168
|
-
if (userData && userData.authority > 1)
|
|
157
|
+
if (userData && userData.authority > 1) {
|
|
158
|
+
if (config.debugMode) logger.info(`[规则匹配] : ${userData.authority}`);
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
169
161
|
} catch {
|
|
170
162
|
}
|
|
171
163
|
if (session.onebot && session.guildId && ((config.minMembers ?? -1) >= 0 || (config.maxCapacity ?? -1) >= 0)) {
|
|
172
164
|
try {
|
|
173
165
|
const stats = await session.onebot.getGroupInfo(session.guildId, true);
|
|
174
|
-
if ((config.minMembers ?? -1) >= 0 && stats.member_count < (config.minMembers ?? 0))
|
|
175
|
-
|
|
166
|
+
if ((config.minMembers ?? -1) >= 0 && stats.member_count < (config.minMembers ?? 0)) {
|
|
167
|
+
if (config.debugMode) logger.info(`[规则判定] 成员检查: ${stats.member_count} < ${config.minMembers}`);
|
|
168
|
+
return `群成员不足 ${config.minMembers} 人`;
|
|
169
|
+
}
|
|
170
|
+
if ((config.maxCapacity ?? -1) >= 0 && stats.max_member_count < (config.maxCapacity ?? 0)) {
|
|
171
|
+
if (config.debugMode) logger.info(`[规则判定] 容量检查: ${stats.max_member_count} < ${config.maxCapacity}`);
|
|
172
|
+
return `群容量不足 ${config.maxCapacity} 人`;
|
|
173
|
+
}
|
|
176
174
|
return true;
|
|
177
175
|
} catch {
|
|
178
176
|
return false;
|
|
@@ -192,12 +190,9 @@ function apply(ctx, config = {}) {
|
|
|
192
190
|
task.timer = setTimeout(async () => {
|
|
193
191
|
if (!activeTasks.has(msgIds[0])) return;
|
|
194
192
|
msgIds.forEach((id) => activeTasks.delete(id));
|
|
195
|
-
|
|
196
|
-
if (
|
|
197
|
-
|
|
198
|
-
if (groupRule?.groupAction) finalAction = groupRule.groupAction;
|
|
199
|
-
}
|
|
200
|
-
const isPass = finalAction === "accept";
|
|
193
|
+
const action = kind === "member" ? config.verifyMode : config.timeoutAction;
|
|
194
|
+
if (action === "manual" || !action) return;
|
|
195
|
+
const isPass = action === "accept";
|
|
201
196
|
await executeAction(session, kind, isPass, isPass ? "" : "等待人工超时,自动拒绝");
|
|
202
197
|
const notifyConfig = config.notifyTarget || "";
|
|
203
198
|
const [targetType, targetId] = notifyConfig.split(":");
|
|
@@ -210,15 +205,24 @@ function apply(ctx, config = {}) {
|
|
|
210
205
|
}, "setupManual");
|
|
211
206
|
const handleEvent = /* @__PURE__ */ __name(async (session, kind) => {
|
|
212
207
|
try {
|
|
208
|
+
if (config.debugMode) logger.info(`[收到请求] 类型:${kind} 数据:${JSON.stringify(session.event?._data || {})}`);
|
|
213
209
|
if (kind === "member") {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const
|
|
220
|
-
|
|
210
|
+
const rule = config.verifyRules?.find((r) => r.guildId === session.guildId);
|
|
211
|
+
if (rule) {
|
|
212
|
+
const rawText = session.event?._data?.comment || "";
|
|
213
|
+
const stats = (rule.minLevel ?? -1) >= 0 && session.onebot && session.userId ? await session.onebot.getStrangerInfo(session.userId, true).catch(() => ({})) : null;
|
|
214
|
+
const keywordMatch = !rule.keyword || new RegExp(rule.keyword, "i").test(rawText);
|
|
215
|
+
const levelMatch = !stats || (stats.qqLevel ?? 0) >= rule.minLevel;
|
|
216
|
+
const isMatch = keywordMatch && levelMatch;
|
|
217
|
+
if (config.debugMode) logger.info(`[规则判定] ${rule.guildId}: 关键词=${keywordMatch}, 等级=${levelMatch}, 结果=${isMatch}`);
|
|
218
|
+
if (isMatch && rule.action) {
|
|
219
|
+
const isApprove = rule.action === "accept";
|
|
220
|
+
await executeAction(session, kind, isApprove, isApprove ? "" : "命中拒绝规则,自动拒绝");
|
|
221
|
+
await sendNotice(session, kind, isApprove ? "auto_pass" : "auto_reject");
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
221
224
|
}
|
|
225
|
+
return await setupManual(session, kind);
|
|
222
226
|
}
|
|
223
227
|
const verdict = await checkCriteria(session, kind);
|
|
224
228
|
if (verdict === true) {
|
|
@@ -228,7 +232,6 @@ function apply(ctx, config = {}) {
|
|
|
228
232
|
await executeAction(session, kind, false, verdict);
|
|
229
233
|
await sendNotice(session, kind, "auto_reject");
|
|
230
234
|
} else {
|
|
231
|
-
if (kind === "member" && config.verifyMode === "strict") return;
|
|
232
235
|
await setupManual(session, kind);
|
|
233
236
|
}
|
|
234
237
|
} catch (error) {
|
|
@@ -259,6 +262,7 @@ function apply(ctx, config = {}) {
|
|
|
259
262
|
activeTask.messages.forEach((msg) => activeTasks.delete(msg));
|
|
260
263
|
const isApprove = cmdMatch[1] === "y" || cmdMatch[1] === "通过";
|
|
261
264
|
const extraInfo = cmdMatch[2]?.trim() || "";
|
|
265
|
+
if (config.debugMode) logger.info(`[人工回复] 用户 ${session.userId} 回复: ${cmdMatch[1]} 备注: ${extraInfo}`);
|
|
262
266
|
const isSuccess = await executeAction(activeTask.session, activeTask.kind, isApprove, isApprove ? "" : extraInfo, isApprove && activeTask.kind === "friend" ? extraInfo : "");
|
|
263
267
|
const replyText = isSuccess ? `已${isApprove ? "通过" : "拒绝"}该请求` : `处理请求失败`;
|
|
264
268
|
await (targetType === "private" ? session.bot.sendPrivateMessage(targetId, replyText) : session.bot.sendMessage(targetId, replyText));
|