koishi-plugin-blacklist-online 0.1.0 → 0.1.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/core.d.ts +1 -1
- package/lib/core.js +16 -16
- package/lib/index.d.ts +1 -1
- package/lib/index.js +8 -7
- package/lib/types.d.ts +4 -3
- package/package.json +1 -1
package/lib/core.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare function isUserAdmin(session: Session, config: PluginConfig, user
|
|
|
5
5
|
export declare function syncBlacklist(ctx: Context, config: PluginConfig): Promise<void>;
|
|
6
6
|
export declare function queueRequest(ctx: Context, type: 'ADD' | 'REMOVE' | 'CANCEL', payload: any): Promise<any>;
|
|
7
7
|
export declare function processOfflineQueue(ctx: Context, config: PluginConfig): Promise<void>;
|
|
8
|
-
export declare function checkAndHandleUser(ctx: Context, config: PluginConfig, session: Session,
|
|
8
|
+
export declare function checkAndHandleUser(ctx: Context, config: PluginConfig, session: Session, user_id: string): Promise<boolean>;
|
|
9
9
|
export declare function parseUserId(input: string): string;
|
|
10
10
|
export declare function scanGuild(ctx: Context, config: PluginConfig, bot: any, // 传入具体的 bot 实例
|
|
11
11
|
guildId: string): Promise<{
|
package/lib/core.js
CHANGED
|
@@ -68,7 +68,7 @@ async function syncBlacklist(ctx, config) {
|
|
|
68
68
|
if (data.upserts?.length)
|
|
69
69
|
await ctx.database.upsert('blacklist_users', data.upserts);
|
|
70
70
|
if (data.deletes?.length)
|
|
71
|
-
await ctx.database.remove('blacklist_users', {
|
|
71
|
+
await ctx.database.remove('blacklist_users', { user_id: data.deletes });
|
|
72
72
|
}
|
|
73
73
|
await ctx.database.upsert('blacklist_meta', [{ key: 'sync_revision', value: newRevision }]);
|
|
74
74
|
logger.info('✅ 同步完成');
|
|
@@ -146,7 +146,7 @@ async function processOfflineQueue(ctx, config) {
|
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
// --- 5. 用户检查核心 ---
|
|
149
|
-
async function checkAndHandleUser(ctx, config, session,
|
|
149
|
+
async function checkAndHandleUser(ctx, config, session, user_id) {
|
|
150
150
|
if (!session.guildId)
|
|
151
151
|
return false;
|
|
152
152
|
const guildSettings = await ctx.database.get('blacklist_guild_settings', { guildId: session.guildId });
|
|
@@ -155,25 +155,25 @@ async function checkAndHandleUser(ctx, config, session, userId) {
|
|
|
155
155
|
return false;
|
|
156
156
|
// 1. 本地白名单 (最高优先级)
|
|
157
157
|
const protectedSet = new Set(config.protectedUsers || []);
|
|
158
|
-
if (protectedSet.has(
|
|
158
|
+
if (protectedSet.has(user_id))
|
|
159
159
|
return false;
|
|
160
160
|
// 2. 查库
|
|
161
|
-
const entries = await ctx.database.get('blacklist_users', {
|
|
161
|
+
const entries = await ctx.database.get('blacklist_users', { user_id, disabled: false });
|
|
162
162
|
if (entries.length === 0)
|
|
163
163
|
return false;
|
|
164
164
|
const entry = entries[0];
|
|
165
165
|
const reason = entry.reason || 'QQ号黑名单';
|
|
166
166
|
// 3. 查管理员
|
|
167
|
-
if (await isUserAdmin(session, config,
|
|
168
|
-
logger.info(`🛡️ 跳过黑名单管理员 ${
|
|
167
|
+
if (await isUserAdmin(session, config, user_id)) {
|
|
168
|
+
logger.info(`🛡️ 跳过黑名单管理员 ${user_id}`);
|
|
169
169
|
return false;
|
|
170
170
|
}
|
|
171
|
-
logger.info(`🎯 [群: ${session.guildId}] 发现黑名单用户: ${
|
|
171
|
+
logger.info(`🎯 [群: ${session.guildId}] 发现黑名单用户: ${user_id} - 原因: ${reason}`);
|
|
172
172
|
// 获取显示名
|
|
173
|
-
let displayName =
|
|
173
|
+
let displayName = user_id;
|
|
174
174
|
try {
|
|
175
|
-
const member = await session.bot.getGuildMember(session.guildId,
|
|
176
|
-
displayName = member.nick || member.user?.name ||
|
|
175
|
+
const member = await session.bot.getGuildMember(session.guildId, user_id);
|
|
176
|
+
displayName = member.nick || member.user?.name || user_id;
|
|
177
177
|
}
|
|
178
178
|
catch {
|
|
179
179
|
}
|
|
@@ -182,7 +182,7 @@ async function checkAndHandleUser(ctx, config, session, userId) {
|
|
|
182
182
|
const tpl = mode === 'notify' ? config.adminNotifyMessage : config.kickNotifyMessage;
|
|
183
183
|
const msg = tpl
|
|
184
184
|
.replace('{user}', displayName)
|
|
185
|
-
.replace('{userId}',
|
|
185
|
+
.replace('{userId}', user_id)
|
|
186
186
|
.replace('{reason}', reason)
|
|
187
187
|
.replace('{guild}', session.guildId);
|
|
188
188
|
// 引用回复
|
|
@@ -193,9 +193,9 @@ async function checkAndHandleUser(ctx, config, session, userId) {
|
|
|
193
193
|
if (mode === 'kick' || mode === 'both') {
|
|
194
194
|
for (let i = 0; i < config.retryAttempts; i++) {
|
|
195
195
|
try {
|
|
196
|
-
await session.bot.kickGuildMember(session.guildId,
|
|
196
|
+
await session.bot.kickGuildMember(session.guildId, user_id);
|
|
197
197
|
kicked = true;
|
|
198
|
-
logger.info(`✅ [群: ${session.guildId}] 成功踢出: ${
|
|
198
|
+
logger.info(`✅ [群: ${session.guildId}] 成功踢出: ${user_id}`);
|
|
199
199
|
break;
|
|
200
200
|
}
|
|
201
201
|
catch (e) {
|
|
@@ -211,9 +211,9 @@ async function checkAndHandleUser(ctx, config, session, userId) {
|
|
|
211
211
|
if (kicked && config.verifyKickResult) {
|
|
212
212
|
await (0, exports.sleep)(2000);
|
|
213
213
|
try {
|
|
214
|
-
await session.bot.getGuildMember(session.guildId,
|
|
214
|
+
await session.bot.getGuildMember(session.guildId, user_id);
|
|
215
215
|
// 如果还能获取到,说明没踢掉
|
|
216
|
-
logger.warn(`⚠️ [群: ${session.guildId}] 踢出验证失败,用户仍在群内: ${
|
|
216
|
+
logger.warn(`⚠️ [群: ${session.guildId}] 踢出验证失败,用户仍在群内: ${user_id}`);
|
|
217
217
|
}
|
|
218
218
|
catch {
|
|
219
219
|
// 获取不到说明踢出成功
|
|
@@ -240,7 +240,7 @@ guildId) {
|
|
|
240
240
|
const members = await bot.getGuildMemberList(guildId);
|
|
241
241
|
// 2. 获取本地黑名单缓存
|
|
242
242
|
const blacklist = await ctx.database.get('blacklist_users', { disabled: false });
|
|
243
|
-
const blacklistSet = new Set(blacklist.map(b => b.
|
|
243
|
+
const blacklistSet = new Set(blacklist.map(b => b.user_id));
|
|
244
244
|
// 3. 筛选目标 (内存操作,极快)
|
|
245
245
|
const targets = members.data.filter((m) => {
|
|
246
246
|
if (!m.user?.id)
|
package/lib/index.d.ts
CHANGED
|
@@ -2,6 +2,6 @@ import { Context, Schema } from 'koishi';
|
|
|
2
2
|
import { PluginConfig } from './types';
|
|
3
3
|
export declare const name = "blacklist-online";
|
|
4
4
|
export declare const inject: string[];
|
|
5
|
-
export declare const usage = "\n## \u529F\u80FD\u8BF4\u660E\n\u4E00\u4E2A\u5F3A\u5927\u7684\u3001\u57FA\u4E8E\u6570\u636E\u5E93\u7684\u7FA4\u7EC4\u9ED1\u540D\u5355\u7BA1\u7406\u63D2\u4EF6\u3002\n- **\
|
|
5
|
+
export declare const usage = "\n## \u529F\u80FD\u8BF4\u660E\n\u4E00\u4E2A\u5F3A\u5927\u7684\u3001\u57FA\u4E8E\u6570\u636E\u5E93\u7684\u7FA4\u7EC4\u9ED1\u540D\u5355\u7BA1\u7406\u63D2\u4EF6\u3002\n- **\u53D7\u4FDD\u62A4\u540D\u5355**: \u914D\u7F6E\u4E2D\u7684\u7528\u6237\u65E0\u6CD5\u88AB\u62C9\u9ED1\u3002\n- **\u5206\u7FA4\u7BA1\u7406**: \u53EF\u4E3A\u6BCF\u4E2A\u7FA4\u72EC\u7ACB\u8BBE\u7F6E\u9ED1\u540D\u5355\u5904\u7406\u6A21\u5F0F\u3002\n- **\u5165\u7FA4\u626B\u63CF**: \u53EF\u914D\u7F6E\u673A\u5668\u4EBA\u5728\u52A0\u5165\u65B0\u7FA4\u7EC4\u65F6\uFF0C\u81EA\u52A8\u626B\u63CF\u7FA4\u5185\u73B0\u6709\u6210\u5458\u3002\n- **\u81EA\u52A8\u62D2\u7EDD**: \u81EA\u52A8\u62D2\u7EDD\u6570\u636E\u5E93\u9ED1\u540D\u5355\u7528\u6237\u7684\u52A0\u7FA4\u7533\u8BF7\u3002\n- **\u624B\u52A8\u626B\u63CF**: \u63D0\u4F9B\u6307\u4EE4\u624B\u52A8\u626B\u63CF\u5F53\u524D\u6216\u5168\u90E8\u7FA4\u7EC4\u3002\n- **\u6743\u9650\u63A7\u5236**: \u6240\u6709\u6307\u4EE4\u5747\u6709\u6743\u9650\u7B49\u7EA7\u63A7\u5236\u3002\n";
|
|
6
6
|
export declare const Config: Schema<PluginConfig>;
|
|
7
7
|
export declare function apply(ctx: Context, config: PluginConfig): void;
|
package/lib/index.js
CHANGED
|
@@ -10,13 +10,9 @@ exports.inject = ['database', 'http'];
|
|
|
10
10
|
exports.usage = `
|
|
11
11
|
## 功能说明
|
|
12
12
|
一个强大的、基于数据库的群组黑名单管理插件。
|
|
13
|
-
- **数据库驱动**: QQ号黑名单存储在数据库中,可通过指令动态增删,支持操作追溯。
|
|
14
13
|
- **受保护名单**: 配置中的用户无法被拉黑。
|
|
15
|
-
- **申请/审批流程**: 普通群管理可提交拉黑申请,由机器人管理员审批,所有流程自动化通知。
|
|
16
14
|
- **分群管理**: 可为每个群独立设置黑名单处理模式。
|
|
17
|
-
- **昵称黑名单**: 支持配置静态的昵称关键词黑名单,并有总开关控制。
|
|
18
15
|
- **入群扫描**: 可配置机器人在加入新群组时,自动扫描群内现有成员。
|
|
19
|
-
- **延迟检查**: 新成员加入后,可配置延迟及周期性昵称检查,防止其修改昵称绕过检测。
|
|
20
16
|
- **自动拒绝**: 自动拒绝数据库黑名单用户的加群申请。
|
|
21
17
|
- **手动扫描**: 提供指令手动扫描当前或全部群组。
|
|
22
18
|
- **权限控制**: 所有指令均有权限等级控制。
|
|
@@ -54,8 +50,13 @@ function apply(ctx, config) {
|
|
|
54
50
|
const logger = ctx.logger('blacklist-online');
|
|
55
51
|
// 1. 扩展数据库
|
|
56
52
|
ctx.model.extend('blacklist_users', {
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
user_id: 'string',
|
|
54
|
+
reason: 'string',
|
|
55
|
+
disabled: { type: 'boolean', initial: false },
|
|
56
|
+
operator_id: 'string',
|
|
57
|
+
source_id: 'string',
|
|
58
|
+
updated_at: 'timestamp'
|
|
59
|
+
}, { primary: 'user_id' });
|
|
59
60
|
ctx.model.extend('blacklist_request_queue', {
|
|
60
61
|
id: 'string', type: 'string', payload: 'json', createdAt: 'timestamp', retryCount: 'unsigned'
|
|
61
62
|
}, { primary: 'id' });
|
|
@@ -94,7 +95,7 @@ function apply(ctx, config) {
|
|
|
94
95
|
if (config.protectedUsers.includes(session.userId))
|
|
95
96
|
return;
|
|
96
97
|
// 查库
|
|
97
|
-
const entries = await ctx.database.get('blacklist_users', {
|
|
98
|
+
const entries = await ctx.database.get('blacklist_users', { user_id: session.userId, disabled: false });
|
|
98
99
|
if (entries.length > 0) {
|
|
99
100
|
try {
|
|
100
101
|
await session.bot.handleGuildRequest(session.messageId, false, config.rejectionMessage);
|
package/lib/types.d.ts
CHANGED
|
@@ -16,11 +16,12 @@ export interface PluginConfig {
|
|
|
16
16
|
autoRejectNotifyMessage: string;
|
|
17
17
|
}
|
|
18
18
|
export interface BlacklistEntry {
|
|
19
|
-
|
|
19
|
+
user_id: string;
|
|
20
20
|
reason: string;
|
|
21
|
-
|
|
21
|
+
operator_id?: string;
|
|
22
|
+
source_id?: string;
|
|
22
23
|
disabled: boolean;
|
|
23
|
-
|
|
24
|
+
updated_at: Date;
|
|
24
25
|
}
|
|
25
26
|
export interface OfflineRequest {
|
|
26
27
|
id: string;
|