koishi-plugin-bind-bot 2.0.0
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/export-utils.d.ts +49 -0
- package/lib/export-utils.js +305 -0
- package/lib/force-bind-utils.d.ts +40 -0
- package/lib/force-bind-utils.js +242 -0
- package/lib/handlers/base.handler.d.ts +61 -0
- package/lib/handlers/base.handler.js +22 -0
- package/lib/handlers/binding.handler.d.ts +45 -0
- package/lib/handlers/binding.handler.js +285 -0
- package/lib/handlers/buid.handler.d.ts +71 -0
- package/lib/handlers/buid.handler.js +694 -0
- package/lib/handlers/index.d.ts +6 -0
- package/lib/handlers/index.js +22 -0
- package/lib/handlers/mcid.handler.d.ts +101 -0
- package/lib/handlers/mcid.handler.js +1045 -0
- package/lib/handlers/tag.handler.d.ts +14 -0
- package/lib/handlers/tag.handler.js +382 -0
- package/lib/handlers/whitelist.handler.d.ts +84 -0
- package/lib/handlers/whitelist.handler.js +1011 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.js +2693 -0
- package/lib/managers/rcon-manager.d.ts +24 -0
- package/lib/managers/rcon-manager.js +308 -0
- package/lib/repositories/mcidbind.repository.d.ts +105 -0
- package/lib/repositories/mcidbind.repository.js +288 -0
- package/lib/repositories/schedule-mute.repository.d.ts +68 -0
- package/lib/repositories/schedule-mute.repository.js +175 -0
- package/lib/types/api.d.ts +135 -0
- package/lib/types/api.js +6 -0
- package/lib/types/common.d.ts +40 -0
- package/lib/types/common.js +6 -0
- package/lib/types/config.d.ts +55 -0
- package/lib/types/config.js +6 -0
- package/lib/types/database.d.ts +47 -0
- package/lib/types/database.js +6 -0
- package/lib/types/index.d.ts +8 -0
- package/lib/types/index.js +28 -0
- package/lib/utils/helpers.d.ts +76 -0
- package/lib/utils/helpers.js +275 -0
- package/lib/utils/logger.d.ts +75 -0
- package/lib/utils/logger.js +134 -0
- package/lib/utils/message-utils.d.ts +46 -0
- package/lib/utils/message-utils.js +234 -0
- package/lib/utils/rate-limiter.d.ts +26 -0
- package/lib/utils/rate-limiter.js +47 -0
- package/lib/utils/session-manager.d.ts +70 -0
- package/lib/utils/session-manager.js +120 -0
- package/package.json +39 -0
- package/readme.md +281 -0
|
@@ -0,0 +1,1011 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WhitelistHandler = void 0;
|
|
4
|
+
const koishi_1 = require("koishi");
|
|
5
|
+
const base_handler_1 = require("./base.handler");
|
|
6
|
+
/**
|
|
7
|
+
* 白名单命令处理器
|
|
8
|
+
* 处理所有 mcid.whitelist 子命令
|
|
9
|
+
*/
|
|
10
|
+
class WhitelistHandler extends base_handler_1.BaseHandler {
|
|
11
|
+
/**
|
|
12
|
+
* 注册白名单相关命令
|
|
13
|
+
*/
|
|
14
|
+
register() {
|
|
15
|
+
const cmd = this.ctx.command('mcid');
|
|
16
|
+
const whitelistCmd = cmd.subcommand('.whitelist', '白名单管理');
|
|
17
|
+
// 注册6个子命令
|
|
18
|
+
this.registerServersCommand(whitelistCmd);
|
|
19
|
+
this.registerAddCommand(whitelistCmd);
|
|
20
|
+
this.registerRemoveCommand(whitelistCmd);
|
|
21
|
+
this.registerResetCommand(whitelistCmd);
|
|
22
|
+
this.registerResetAllCommand(whitelistCmd);
|
|
23
|
+
this.registerAddAllCommand(whitelistCmd);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 列出所有可用的服务器
|
|
27
|
+
*/
|
|
28
|
+
registerServersCommand(parent) {
|
|
29
|
+
parent.subcommand('.servers', '列出所有可用的服务器')
|
|
30
|
+
.action(async ({ session }) => {
|
|
31
|
+
try {
|
|
32
|
+
const normalizedUserId = this.deps.normalizeQQId(session.userId);
|
|
33
|
+
this.logger.info('白名单', `QQ(${normalizedUserId})查询可用服务器列表`);
|
|
34
|
+
// 获取启用的服务器
|
|
35
|
+
const enabledServers = this.config.servers?.filter(server => server.enabled !== false) || [];
|
|
36
|
+
if (!enabledServers || enabledServers.length === 0) {
|
|
37
|
+
this.logger.info('白名单', `未配置或启用任何服务器`);
|
|
38
|
+
return this.deps.sendMessage(session, [koishi_1.h.text('当前未配置或启用任何服务器')]);
|
|
39
|
+
}
|
|
40
|
+
// 检查用户是否绑定了MC账号
|
|
41
|
+
const userBind = await this.deps.getBindInfo(normalizedUserId);
|
|
42
|
+
if (!userBind || !userBind.mcUsername) {
|
|
43
|
+
this.logger.warn('白名单', `QQ(${normalizedUserId})未绑定MC账号,无法显示白名单状态`);
|
|
44
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`您尚未绑定MC账号,请先使用 ${this.deps.formatCommand('mcid bind <用户名>')} 命令绑定账号,然后再查看服务器列表。`)]);
|
|
45
|
+
}
|
|
46
|
+
// 圈数字映射(1-20)
|
|
47
|
+
const circledNumbers = ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩',
|
|
48
|
+
'⑪', '⑫', '⑬', '⑭', '⑮', '⑯', '⑰', '⑱', '⑲', '⑳'];
|
|
49
|
+
// 格式化服务器列表
|
|
50
|
+
const serverList = enabledServers.map((server, index) => {
|
|
51
|
+
// 获取此用户是否已加入该服务器的白名单
|
|
52
|
+
const hasWhitelist = userBind ? this.isInServerWhitelist(userBind, server.id) : false;
|
|
53
|
+
// 使用圈数字作为序号
|
|
54
|
+
const circledNumber = index < circledNumbers.length ? circledNumbers[index] : `${index + 1}.`;
|
|
55
|
+
// 构建服务器信息显示文本
|
|
56
|
+
let serverInfo = `${circledNumber} ${server.name}`;
|
|
57
|
+
// 添加状态标记
|
|
58
|
+
if (hasWhitelist) {
|
|
59
|
+
serverInfo += ' [✓ 已加入]';
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
serverInfo += ' [未加入]';
|
|
63
|
+
}
|
|
64
|
+
// 添加服务器ID信息
|
|
65
|
+
serverInfo += `\n ID: ${server.id}`;
|
|
66
|
+
// 添加服务器状态信息
|
|
67
|
+
serverInfo += "\n 状态: " + (server.enabled === false ? '已停用' : '已启用');
|
|
68
|
+
// 添加申请权限信息
|
|
69
|
+
serverInfo += "\n 权限: " + (server.allowSelfApply ? '允许自助申请' : '仅管理员可操作');
|
|
70
|
+
// 只有当设置了地址时才显示地址行
|
|
71
|
+
if (server.displayAddress && server.displayAddress.trim()) {
|
|
72
|
+
serverInfo += "\n 地址: " + server.displayAddress;
|
|
73
|
+
}
|
|
74
|
+
// 只有当设置了说明信息时才显示说明行
|
|
75
|
+
if (server.description && server.description.trim()) {
|
|
76
|
+
serverInfo += "\n 说明: " + server.description;
|
|
77
|
+
}
|
|
78
|
+
return serverInfo;
|
|
79
|
+
}).join('\n\n'); // 使用双换行分隔不同服务器,增强可读性
|
|
80
|
+
this.logger.info('白名单', `成功: QQ(${normalizedUserId})获取了服务器列表,共${enabledServers.length}个服务器`);
|
|
81
|
+
const displayUsername = userBind.mcUsername && !userBind.mcUsername.startsWith('_temp_') ? userBind.mcUsername : '未绑定MC账号';
|
|
82
|
+
return this.deps.sendMessage(session, [
|
|
83
|
+
koishi_1.h.text(`${displayUsername} 的可用服务器列表:\n\n${serverList}\n\n使用 ${this.deps.formatCommand('mcid whitelist add <服务器名称或ID>')} 申请白名单`)
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
const normalizedUserId = this.deps.normalizeQQId(session.userId);
|
|
88
|
+
this.logger.error('白名单', `QQ(${normalizedUserId})查询服务器列表失败: ${error.message}`);
|
|
89
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(this.getFriendlyErrorMessage(error))]);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 添加白名单
|
|
95
|
+
*/
|
|
96
|
+
registerAddCommand(parent) {
|
|
97
|
+
parent.subcommand('.add <serverIdOrName:string> [...targets:string]', '申请/添加服务器白名单')
|
|
98
|
+
.action(async ({ session }, serverIdOrName, ...targets) => {
|
|
99
|
+
try {
|
|
100
|
+
const normalizedUserId = this.deps.normalizeQQId(session.userId);
|
|
101
|
+
// 检查服务器名称或ID
|
|
102
|
+
if (!serverIdOrName) {
|
|
103
|
+
this.logger.warn('白名单', `QQ(${normalizedUserId})未提供服务器名称或ID`);
|
|
104
|
+
return this.deps.sendMessage(session, [koishi_1.h.text('请提供服务器名称或ID\n使用 mcid whitelist servers 查看可用服务器列表')]);
|
|
105
|
+
}
|
|
106
|
+
// 获取服务器配置
|
|
107
|
+
const server = this.getServerConfigByIdOrName(serverIdOrName);
|
|
108
|
+
if (!server) {
|
|
109
|
+
this.logger.warn('白名单', `QQ(${normalizedUserId})提供的服务器名称或ID"${serverIdOrName}"无效`);
|
|
110
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`未找到名称或ID为"${serverIdOrName}"的服务器\n使用 mcid whitelist servers 查看可用服务器列表`)]);
|
|
111
|
+
}
|
|
112
|
+
// 如果有指定目标用户(批量操作或单个用户管理)
|
|
113
|
+
if (targets && targets.length > 0) {
|
|
114
|
+
// 检查权限
|
|
115
|
+
if (!await this.isAdmin(session.userId)) {
|
|
116
|
+
this.logger.warn('白名单', `权限不足: QQ(${normalizedUserId})不是管理员,无法为其他用户添加白名单`);
|
|
117
|
+
return this.deps.sendMessage(session, [koishi_1.h.text('只有管理员才能为其他用户添加白名单')]);
|
|
118
|
+
}
|
|
119
|
+
// 检查是否为标签(优先检查标签名,没有匹配标签再按QQ号处理)
|
|
120
|
+
if (targets.length === 1) {
|
|
121
|
+
const targetValue = targets[0];
|
|
122
|
+
// 首先检查是否存在该标签名
|
|
123
|
+
const allBinds = await this.repos.mcidbind.findAll();
|
|
124
|
+
const usersWithTag = allBinds.filter(bind => bind.tags && bind.tags.includes(targetValue) && bind.mcUsername && !bind.mcUsername.startsWith('_temp_'));
|
|
125
|
+
if (usersWithTag.length > 0) {
|
|
126
|
+
// 作为标签处理
|
|
127
|
+
const tagName = targetValue;
|
|
128
|
+
this.logger.info('白名单', `管理员QQ(${normalizedUserId})尝试为标签"${tagName}"的所有用户添加服务器"${server.name}"白名单`);
|
|
129
|
+
// 转换为用户ID数组
|
|
130
|
+
targets = usersWithTag.map(bind => bind.qqId);
|
|
131
|
+
this.logger.info('白名单', `找到${targets.length}个有标签"${tagName}"的已绑定用户`);
|
|
132
|
+
await this.deps.sendMessage(session, [koishi_1.h.text(`找到${targets.length}个有标签"${tagName}"的已绑定用户,开始添加白名单...`)]);
|
|
133
|
+
}
|
|
134
|
+
// 如果没有找到标签,将继续按单个用户处理
|
|
135
|
+
}
|
|
136
|
+
// 单个用户的简洁处理逻辑
|
|
137
|
+
if (targets.length === 1) {
|
|
138
|
+
const target = targets[0];
|
|
139
|
+
const normalizedTargetId = this.deps.normalizeQQId(target);
|
|
140
|
+
this.logger.info('白名单', `QQ(${normalizedUserId})尝试为QQ(${normalizedTargetId})添加服务器"${server.name}"白名单`);
|
|
141
|
+
// 获取目标用户的绑定信息
|
|
142
|
+
const targetBind = await this.deps.getBindInfo(normalizedTargetId);
|
|
143
|
+
if (!targetBind || !targetBind.mcUsername) {
|
|
144
|
+
this.logger.warn('白名单', `QQ(${normalizedTargetId})未绑定MC账号`);
|
|
145
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`用户 ${normalizedTargetId} 尚未绑定MC账号,无法添加白名单`)]);
|
|
146
|
+
}
|
|
147
|
+
// 检查是否已在白名单中
|
|
148
|
+
if (this.isInServerWhitelist(targetBind, server.id)) {
|
|
149
|
+
this.logger.warn('白名单', `QQ(${normalizedTargetId})已在服务器"${server.name}"的白名单中`);
|
|
150
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`用户 ${normalizedTargetId} 已在服务器"${server.name}"的白名单中`)]);
|
|
151
|
+
}
|
|
152
|
+
// 执行添加白名单操作
|
|
153
|
+
const result = await this.addServerWhitelist(targetBind, server);
|
|
154
|
+
if (result) {
|
|
155
|
+
this.logger.info('白名单', `成功: 管理员QQ(${normalizedUserId})为QQ(${normalizedTargetId})添加了服务器"${server.name}"的白名单`);
|
|
156
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`已成功为用户 ${normalizedTargetId} 添加服务器"${server.name}"的白名单`)]);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
this.logger.error('白名单', `管理员QQ(${normalizedUserId})为QQ(${normalizedTargetId})添加服务器"${server.name}"白名单失败`);
|
|
160
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`为用户 ${normalizedTargetId} 添加服务器"${server.name}"白名单失败,请检查RCON连接和命令配置`)]);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// 批量用户的详细处理逻辑
|
|
164
|
+
this.logger.info('白名单', `QQ(${normalizedUserId})尝试批量为${targets.length}个用户添加服务器"${server.name}"白名单`);
|
|
165
|
+
// 发送开始处理的通知
|
|
166
|
+
await this.deps.sendMessage(session, [koishi_1.h.text(`开始为${targets.length}个用户添加服务器"${server.name}"的白名单,请稍候...`)]);
|
|
167
|
+
// 统计信息
|
|
168
|
+
let successCount = 0;
|
|
169
|
+
let failCount = 0;
|
|
170
|
+
let skipCount = 0;
|
|
171
|
+
const results = [];
|
|
172
|
+
// 处理每个目标用户
|
|
173
|
+
for (let i = 0; i < targets.length; i++) {
|
|
174
|
+
const target = targets[i];
|
|
175
|
+
const normalizedTargetId = this.deps.normalizeQQId(target);
|
|
176
|
+
try {
|
|
177
|
+
// 获取目标用户的绑定信息
|
|
178
|
+
const targetBind = await this.deps.getBindInfo(normalizedTargetId);
|
|
179
|
+
if (!targetBind || !targetBind.mcUsername) {
|
|
180
|
+
failCount++;
|
|
181
|
+
results.push(`❌ ${normalizedTargetId}: 未绑定MC账号`);
|
|
182
|
+
this.logger.warn('白名单', `QQ(${normalizedTargetId})未绑定MC账号`);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
// 检查是否已在白名单中
|
|
186
|
+
if (this.isInServerWhitelist(targetBind, server.id)) {
|
|
187
|
+
skipCount++;
|
|
188
|
+
results.push(`⏭️ ${normalizedTargetId}: 已在白名单中`);
|
|
189
|
+
this.logger.warn('白名单', `QQ(${normalizedTargetId})已在服务器"${server.name}"的白名单中`);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
// 执行添加白名单操作
|
|
193
|
+
const result = await this.addServerWhitelist(targetBind, server);
|
|
194
|
+
if (result) {
|
|
195
|
+
successCount++;
|
|
196
|
+
results.push(`✅ ${normalizedTargetId}: 添加成功`);
|
|
197
|
+
this.logger.info('白名单', `成功: 管理员QQ(${normalizedUserId})为QQ(${normalizedTargetId})添加了服务器"${server.name}"的白名单`);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
failCount++;
|
|
201
|
+
results.push(`❌ ${normalizedTargetId}: 添加失败`);
|
|
202
|
+
this.logger.error('白名单', `管理员QQ(${normalizedUserId})为QQ(${normalizedTargetId})添加服务器"${server.name}"白名单失败`);
|
|
203
|
+
}
|
|
204
|
+
// 批量操作时添加适当延迟,避免过载
|
|
205
|
+
if (i < targets.length - 1) {
|
|
206
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
207
|
+
}
|
|
208
|
+
// 每处理5个用户发送一次进度更新(仅在批量操作时)
|
|
209
|
+
if (targets.length > 5 && (i + 1) % 5 === 0) {
|
|
210
|
+
const progress = Math.round(((i + 1) / targets.length) * 100);
|
|
211
|
+
await this.deps.sendMessage(session, [koishi_1.h.text(`批量添加白名单进度: ${progress}% (${i + 1}/${targets.length})\n成功: ${successCount} | 失败: ${failCount} | 跳过: ${skipCount}`)]);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
failCount++;
|
|
216
|
+
results.push(`❌ ${normalizedTargetId}: 处理出错`);
|
|
217
|
+
this.logger.error('白名单', `处理用户QQ(${normalizedTargetId})时出错: ${error.message}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// 生成结果报告
|
|
221
|
+
let resultMessage = `批量添加服务器"${server.name}"白名单完成\n共处理${targets.length}个用户\n✅ 成功: ${successCount} 个\n❌ 失败: ${failCount} 个\n⏭️ 跳过: ${skipCount} 个`;
|
|
222
|
+
// 如果有详细结果且用户数量不太多,显示详细信息
|
|
223
|
+
if (targets.length <= 10) {
|
|
224
|
+
resultMessage += '\n\n详细结果:\n' + results.join('\n');
|
|
225
|
+
}
|
|
226
|
+
this.logger.info('白名单', `批量操作完成: 管理员QQ(${normalizedUserId})为${targets.length}个用户添加服务器"${server.name}"白名单,成功: ${successCount},失败: ${failCount},跳过: ${skipCount}`);
|
|
227
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(resultMessage)]);
|
|
228
|
+
}
|
|
229
|
+
// 为自己添加白名单(原有逻辑保持不变)
|
|
230
|
+
this.logger.info('白名单', `QQ(${normalizedUserId})尝试为自己添加服务器"${server.name}"白名单`);
|
|
231
|
+
// 检查服务器是否允许自助申请
|
|
232
|
+
if (!server.allowSelfApply && !await this.isAdmin(session.userId)) {
|
|
233
|
+
this.logger.warn('白名单', `服务器"${server.name}"不允许自助申请,且QQ(${normalizedUserId})不是管理员`);
|
|
234
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`服务器"${server.name}"不允许自助申请白名单,请联系管理员`)]);
|
|
235
|
+
}
|
|
236
|
+
// 获取自己的绑定信息
|
|
237
|
+
const selfBind = await this.deps.getBindInfo(normalizedUserId);
|
|
238
|
+
if (!selfBind || !selfBind.mcUsername) {
|
|
239
|
+
this.logger.warn('白名单', `QQ(${normalizedUserId})未绑定MC账号`);
|
|
240
|
+
return this.deps.sendMessage(session, [koishi_1.h.text('您尚未绑定MC账号,请先使用 ' + this.deps.formatCommand('mcid bind <用户名>') + ' 进行绑定')]);
|
|
241
|
+
}
|
|
242
|
+
// 检查是否已在白名单中
|
|
243
|
+
if (this.isInServerWhitelist(selfBind, server.id)) {
|
|
244
|
+
this.logger.warn('白名单', `QQ(${normalizedUserId})已在服务器"${server.name}"的白名单中`);
|
|
245
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`您已在服务器"${server.name}"的白名单中`)]);
|
|
246
|
+
}
|
|
247
|
+
// 执行添加白名单操作
|
|
248
|
+
const result = await this.addServerWhitelist(selfBind, server);
|
|
249
|
+
if (result) {
|
|
250
|
+
this.logger.info('白名单', `成功: QQ(${normalizedUserId})添加了服务器"${server.name}"的白名单`);
|
|
251
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`已成功添加服务器"${server.name}"的白名单`)]);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
this.logger.error('白名单', `QQ(${normalizedUserId})添加服务器"${server.name}"白名单失败`);
|
|
255
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`添加服务器"${server.name}"白名单失败,请联系管理员`)]);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
const normalizedUserId = this.deps.normalizeQQId(session.userId);
|
|
260
|
+
this.logger.error('白名单', `QQ(${normalizedUserId})添加白名单失败: ${error.message}`);
|
|
261
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(this.getFriendlyErrorMessage(error))]);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* 移除白名单
|
|
267
|
+
*/
|
|
268
|
+
registerRemoveCommand(parent) {
|
|
269
|
+
parent.subcommand('.remove <serverIdOrName:string> [...targets:string]', '[管理员]移除服务器白名单')
|
|
270
|
+
.action(async ({ session }, serverIdOrName, ...targets) => {
|
|
271
|
+
try {
|
|
272
|
+
const normalizedUserId = this.deps.normalizeQQId(session.userId);
|
|
273
|
+
// 检查权限,只有管理员可以移除白名单
|
|
274
|
+
if (!await this.isAdmin(session.userId)) {
|
|
275
|
+
this.logger.warn('白名单', `权限不足: QQ(${normalizedUserId})不是管理员,无法移除白名单`);
|
|
276
|
+
return this.deps.sendMessage(session, [koishi_1.h.text('只有管理员才能移除白名单')]);
|
|
277
|
+
}
|
|
278
|
+
// 检查服务器名称或ID
|
|
279
|
+
if (!serverIdOrName) {
|
|
280
|
+
this.logger.warn('白名单', `QQ(${normalizedUserId})未提供服务器名称或ID`);
|
|
281
|
+
return this.deps.sendMessage(session, [koishi_1.h.text('请提供服务器名称或ID\n使用 mcid whitelist servers 查看可用服务器列表')]);
|
|
282
|
+
}
|
|
283
|
+
// 获取服务器配置
|
|
284
|
+
const server = this.getServerConfigByIdOrName(serverIdOrName);
|
|
285
|
+
if (!server) {
|
|
286
|
+
this.logger.warn('白名单', `QQ(${normalizedUserId})提供的服务器名称或ID"${serverIdOrName}"无效`);
|
|
287
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`未找到名称或ID为"${serverIdOrName}"的服务器\n使用 mcid whitelist servers 查看可用服务器列表`)]);
|
|
288
|
+
}
|
|
289
|
+
// 如果有指定目标用户(批量操作或单个用户管理)
|
|
290
|
+
if (targets && targets.length > 0) {
|
|
291
|
+
// 检查是否为标签(优先检查标签名,没有匹配标签再按QQ号处理)
|
|
292
|
+
if (targets.length === 1) {
|
|
293
|
+
const targetValue = targets[0];
|
|
294
|
+
// 首先检查是否存在该标签名
|
|
295
|
+
const allBinds = await this.repos.mcidbind.findAll();
|
|
296
|
+
const usersWithTag = allBinds.filter(bind => bind.tags && bind.tags.includes(targetValue) && bind.mcUsername && !bind.mcUsername.startsWith('_temp_'));
|
|
297
|
+
if (usersWithTag.length > 0) {
|
|
298
|
+
// 作为标签处理
|
|
299
|
+
const tagName = targetValue;
|
|
300
|
+
this.logger.info('白名单', `管理员QQ(${normalizedUserId})尝试为标签"${tagName}"的所有用户移除服务器"${server.name}"白名单`);
|
|
301
|
+
// 转换为用户ID数组
|
|
302
|
+
targets = usersWithTag.map(bind => bind.qqId);
|
|
303
|
+
this.logger.info('白名单', `找到${targets.length}个有标签"${tagName}"的已绑定用户`);
|
|
304
|
+
await this.deps.sendMessage(session, [koishi_1.h.text(`找到${targets.length}个有标签"${tagName}"的已绑定用户,开始移除白名单...`)]);
|
|
305
|
+
}
|
|
306
|
+
// 如果没有找到标签,将继续按单个用户处理
|
|
307
|
+
}
|
|
308
|
+
// 单个用户的简洁处理逻辑
|
|
309
|
+
if (targets.length === 1) {
|
|
310
|
+
const target = targets[0];
|
|
311
|
+
const normalizedTargetId = this.deps.normalizeQQId(target);
|
|
312
|
+
this.logger.info('白名单', `管理员QQ(${normalizedUserId})尝试为QQ(${normalizedTargetId})移除服务器"${server.name}"白名单`);
|
|
313
|
+
// 获取目标用户的绑定信息
|
|
314
|
+
const targetBind = await this.deps.getBindInfo(normalizedTargetId);
|
|
315
|
+
if (!targetBind || !targetBind.mcUsername) {
|
|
316
|
+
this.logger.warn('白名单', `QQ(${normalizedTargetId})未绑定MC账号`);
|
|
317
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`用户 ${normalizedTargetId} 尚未绑定MC账号,无法移除白名单`)]);
|
|
318
|
+
}
|
|
319
|
+
// 检查是否在白名单中
|
|
320
|
+
if (!this.isInServerWhitelist(targetBind, server.id)) {
|
|
321
|
+
this.logger.warn('白名单', `QQ(${normalizedTargetId})不在服务器"${server.name}"的白名单中`);
|
|
322
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`用户 ${normalizedTargetId} 不在服务器"${server.name}"的白名单中`)]);
|
|
323
|
+
}
|
|
324
|
+
// 执行移除白名单操作
|
|
325
|
+
const result = await this.removeServerWhitelist(targetBind, server);
|
|
326
|
+
if (result) {
|
|
327
|
+
this.logger.info('白名单', `成功: 管理员QQ(${normalizedUserId})为QQ(${normalizedTargetId})移除了服务器"${server.name}"的白名单`);
|
|
328
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`已成功为用户 ${normalizedTargetId} 移除服务器"${server.name}"的白名单`)]);
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
this.logger.error('白名单', `管理员QQ(${normalizedUserId})为QQ(${normalizedTargetId})移除服务器"${server.name}"白名单失败`);
|
|
332
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`为用户 ${normalizedTargetId} 移除服务器"${server.name}"白名单失败,请检查RCON连接和命令配置`)]);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
// 批量用户的详细处理逻辑
|
|
336
|
+
this.logger.info('白名单', `管理员QQ(${normalizedUserId})尝试批量为${targets.length}个用户移除服务器"${server.name}"白名单`);
|
|
337
|
+
// 发送开始处理的通知
|
|
338
|
+
await this.deps.sendMessage(session, [koishi_1.h.text(`开始为${targets.length}个用户移除服务器"${server.name}"的白名单,请稍候...`)]);
|
|
339
|
+
// 统计信息
|
|
340
|
+
let successCount = 0;
|
|
341
|
+
let failCount = 0;
|
|
342
|
+
let skipCount = 0;
|
|
343
|
+
const results = [];
|
|
344
|
+
// 处理每个目标用户
|
|
345
|
+
for (let i = 0; i < targets.length; i++) {
|
|
346
|
+
const target = targets[i];
|
|
347
|
+
const normalizedTargetId = this.deps.normalizeQQId(target);
|
|
348
|
+
try {
|
|
349
|
+
// 获取目标用户的绑定信息
|
|
350
|
+
const targetBind = await this.deps.getBindInfo(normalizedTargetId);
|
|
351
|
+
if (!targetBind || !targetBind.mcUsername) {
|
|
352
|
+
failCount++;
|
|
353
|
+
results.push(`❌ ${normalizedTargetId}: 未绑定MC账号`);
|
|
354
|
+
this.logger.warn('白名单', `QQ(${normalizedTargetId})未绑定MC账号`);
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
// 检查是否在白名单中
|
|
358
|
+
if (!this.isInServerWhitelist(targetBind, server.id)) {
|
|
359
|
+
skipCount++;
|
|
360
|
+
results.push(`⏭️ ${normalizedTargetId}: 不在白名单中`);
|
|
361
|
+
this.logger.warn('白名单', `QQ(${normalizedTargetId})不在服务器"${server.name}"的白名单中`);
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
// 执行移除白名单操作
|
|
365
|
+
const result = await this.removeServerWhitelist(targetBind, server);
|
|
366
|
+
if (result) {
|
|
367
|
+
successCount++;
|
|
368
|
+
results.push(`✅ ${normalizedTargetId}: 移除成功`);
|
|
369
|
+
this.logger.info('白名单', `成功: 管理员QQ(${normalizedUserId})为QQ(${normalizedTargetId})移除了服务器"${server.name}"的白名单`);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
failCount++;
|
|
373
|
+
results.push(`❌ ${normalizedTargetId}: 移除失败`);
|
|
374
|
+
this.logger.error('白名单', `管理员QQ(${normalizedUserId})为QQ(${normalizedTargetId})移除服务器"${server.name}"白名单失败`);
|
|
375
|
+
}
|
|
376
|
+
// 批量操作时添加适当延迟,避免过载
|
|
377
|
+
if (i < targets.length - 1) {
|
|
378
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
379
|
+
}
|
|
380
|
+
// 每处理5个用户发送一次进度更新(仅在批量操作时)
|
|
381
|
+
if (targets.length > 5 && (i + 1) % 5 === 0) {
|
|
382
|
+
const progress = Math.round(((i + 1) / targets.length) * 100);
|
|
383
|
+
await this.deps.sendMessage(session, [koishi_1.h.text(`批量移除白名单进度: ${progress}% (${i + 1}/${targets.length})\n成功: ${successCount} | 失败: ${failCount} | 跳过: ${skipCount}`)]);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
catch (error) {
|
|
387
|
+
failCount++;
|
|
388
|
+
results.push(`❌ ${normalizedTargetId}: 处理出错`);
|
|
389
|
+
this.logger.error('白名单', `处理用户QQ(${normalizedTargetId})时出错: ${error.message}`);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// 生成结果报告
|
|
393
|
+
let resultMessage = `批量移除服务器"${server.name}"白名单完成\n共处理${targets.length}个用户\n✅ 成功: ${successCount} 个\n❌ 失败: ${failCount} 个\n⏭️ 跳过: ${skipCount} 个`;
|
|
394
|
+
// 如果有详细结果且用户数量不太多,显示详细信息
|
|
395
|
+
if (targets.length <= 10) {
|
|
396
|
+
resultMessage += '\n\n详细结果:\n' + results.join('\n');
|
|
397
|
+
}
|
|
398
|
+
this.logger.info('白名单', `批量操作完成: 管理员QQ(${normalizedUserId})为${targets.length}个用户移除服务器"${server.name}"白名单,成功: ${successCount},失败: ${failCount},跳过: ${skipCount}`);
|
|
399
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(resultMessage)]);
|
|
400
|
+
}
|
|
401
|
+
// 为自己移除白名单(原有逻辑保持不变)
|
|
402
|
+
this.logger.info('白名单', `管理员QQ(${normalizedUserId})尝试为自己移除服务器"${server.name}"白名单`);
|
|
403
|
+
// 获取自己的绑定信息
|
|
404
|
+
const selfBind = await this.deps.getBindInfo(normalizedUserId);
|
|
405
|
+
if (!selfBind || !selfBind.mcUsername) {
|
|
406
|
+
this.logger.warn('白名单', `QQ(${normalizedUserId})未绑定MC账号`);
|
|
407
|
+
return this.deps.sendMessage(session, [koishi_1.h.text('您尚未绑定MC账号,请先使用 ' + this.deps.formatCommand('mcid bind <用户名>') + ' 进行绑定')]);
|
|
408
|
+
}
|
|
409
|
+
// 检查是否在白名单中
|
|
410
|
+
if (!this.isInServerWhitelist(selfBind, server.id)) {
|
|
411
|
+
this.logger.warn('白名单', `QQ(${normalizedUserId})不在服务器"${server.name}"的白名单中`);
|
|
412
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`您不在服务器"${server.name}"的白名单中`)]);
|
|
413
|
+
}
|
|
414
|
+
// 执行移除白名单操作
|
|
415
|
+
const result = await this.removeServerWhitelist(selfBind, server);
|
|
416
|
+
if (result) {
|
|
417
|
+
this.logger.info('白名单', `成功: 管理员QQ(${normalizedUserId})移除了自己服务器"${server.name}"的白名单`);
|
|
418
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`已成功移除服务器"${server.name}"的白名单`)]);
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
this.logger.error('白名单', `管理员QQ(${normalizedUserId})移除服务器"${server.name}"白名单失败`);
|
|
422
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`移除服务器"${server.name}"白名单失败,请检查RCON连接和命令配置`)]);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
catch (error) {
|
|
426
|
+
const normalizedUserId = this.deps.normalizeQQId(session.userId);
|
|
427
|
+
this.logger.error('白名单', `QQ(${normalizedUserId})移除白名单失败: ${error.message}`);
|
|
428
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(this.getFriendlyErrorMessage(error))]);
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* 重置服务器所有白名单记录
|
|
434
|
+
*/
|
|
435
|
+
registerResetCommand(parent) {
|
|
436
|
+
parent.subcommand('.reset <serverIdOrName:string>', '[主人]重置服务器所有白名单记录')
|
|
437
|
+
.action(async ({ session }, serverIdOrName) => {
|
|
438
|
+
try {
|
|
439
|
+
const normalizedUserId = this.deps.normalizeQQId(session.userId);
|
|
440
|
+
// 检查是否为主人
|
|
441
|
+
if (!this.isMaster(session.userId)) {
|
|
442
|
+
this.logger.warn('重置白名单', `权限不足: QQ(${normalizedUserId})不是主人,无法重置白名单数据库`);
|
|
443
|
+
return this.deps.sendMessage(session, [koishi_1.h.text('只有主人才能重置服务器白名单数据库')]);
|
|
444
|
+
}
|
|
445
|
+
// 检查服务器ID或名称
|
|
446
|
+
if (!serverIdOrName) {
|
|
447
|
+
this.logger.warn('重置白名单', `QQ(${normalizedUserId})未提供服务器ID或名称`);
|
|
448
|
+
return this.deps.sendMessage(session, [koishi_1.h.text('请提供服务器ID或名称\n使用 mcid whitelist servers 查看可用服务器列表')]);
|
|
449
|
+
}
|
|
450
|
+
// 直接使用提供的ID进行删除,不验证服务器是否存在于配置中
|
|
451
|
+
const serverId = serverIdOrName;
|
|
452
|
+
this.logger.info('重置白名单', `主人QQ(${normalizedUserId})正在重置服务器ID"${serverId}"的白名单数据库记录`);
|
|
453
|
+
// 查询所有用户绑定记录
|
|
454
|
+
const allBinds = await this.repos.mcidbind.findAll();
|
|
455
|
+
this.logger.info('重置白名单', `共有${allBinds.length}条记录需要检查`);
|
|
456
|
+
// 统计信息
|
|
457
|
+
let processedCount = 0;
|
|
458
|
+
let updatedCount = 0;
|
|
459
|
+
// 处理每条记录
|
|
460
|
+
for (const bind of allBinds) {
|
|
461
|
+
processedCount++;
|
|
462
|
+
// 检查该用户是否有此服务器的白名单
|
|
463
|
+
if (bind.whitelist && bind.whitelist.includes(serverId)) {
|
|
464
|
+
// 更新记录,移除该服务器的白名单
|
|
465
|
+
const newWhitelist = bind.whitelist.filter(id => id !== serverId);
|
|
466
|
+
await this.repos.mcidbind.update(bind.qqId, {
|
|
467
|
+
whitelist: newWhitelist
|
|
468
|
+
});
|
|
469
|
+
updatedCount++;
|
|
470
|
+
this.logger.info('重置白名单', `已从QQ(${bind.qqId})的白名单记录中移除服务器ID"${serverId}"`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
this.logger.info('重置白名单', `成功: 主人QQ(${normalizedUserId})重置了服务器ID"${serverId}"的白名单数据库,共处理${processedCount}条记录,更新${updatedCount}条记录`);
|
|
474
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`已成功重置服务器ID"${serverId}"的白名单数据库记录\n共处理${processedCount}条记录,更新${updatedCount}条记录\n\n注意:此操作仅清除数据库记录,如需同时清除服务器上的白名单,请使用RCON命令手动操作`)]);
|
|
475
|
+
}
|
|
476
|
+
catch (error) {
|
|
477
|
+
const normalizedUserId = this.deps.normalizeQQId(session.userId);
|
|
478
|
+
this.logger.error('重置白名单', `QQ(${normalizedUserId})重置白名单数据库失败: ${error.message}`);
|
|
479
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(this.getFriendlyErrorMessage(error))]);
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* 重置所有未在服务器配置中的白名单ID
|
|
485
|
+
*/
|
|
486
|
+
registerResetAllCommand(parent) {
|
|
487
|
+
parent.subcommand('.resetall', '[主人]清理所有未在服务器配置列表中的白名单ID')
|
|
488
|
+
.action(async ({ session }) => {
|
|
489
|
+
try {
|
|
490
|
+
const normalizedUserId = this.deps.normalizeQQId(session.userId);
|
|
491
|
+
// 检查是否为主人
|
|
492
|
+
if (!this.isMaster(session.userId)) {
|
|
493
|
+
this.logger.warn('清理白名单', `权限不足: QQ(${normalizedUserId})不是主人,无法执行清理操作`);
|
|
494
|
+
return this.deps.sendMessage(session, [koishi_1.h.text('只有主人才能执行白名单清理操作')]);
|
|
495
|
+
}
|
|
496
|
+
// 获取当前配置中所有有效的服务器ID
|
|
497
|
+
const validServerIds = new Set(this.config.servers?.map(server => server.id) || []);
|
|
498
|
+
this.logger.info('清理白名单', `主人QQ(${normalizedUserId})开始清理白名单,有效服务器ID: ${Array.from(validServerIds).join(', ')}`);
|
|
499
|
+
// 查询所有用户绑定记录
|
|
500
|
+
const allBinds = await this.repos.mcidbind.findAll();
|
|
501
|
+
// 统计信息
|
|
502
|
+
let processedCount = 0;
|
|
503
|
+
let updatedCount = 0;
|
|
504
|
+
let removedIdsTotal = 0;
|
|
505
|
+
const invalidIdsFound = new Set();
|
|
506
|
+
// 处理每条记录
|
|
507
|
+
for (const bind of allBinds) {
|
|
508
|
+
processedCount++;
|
|
509
|
+
if (bind.whitelist && bind.whitelist.length > 0) {
|
|
510
|
+
// 分离有效和无效的服务器ID
|
|
511
|
+
const validIds = bind.whitelist.filter(id => validServerIds.has(id));
|
|
512
|
+
const invalidIds = bind.whitelist.filter(id => !validServerIds.has(id));
|
|
513
|
+
// 记录发现的无效ID
|
|
514
|
+
invalidIds.forEach(id => invalidIdsFound.add(id));
|
|
515
|
+
// 如果有无效ID需要移除
|
|
516
|
+
if (invalidIds.length > 0) {
|
|
517
|
+
await this.repos.mcidbind.update(bind.qqId, {
|
|
518
|
+
whitelist: validIds
|
|
519
|
+
});
|
|
520
|
+
updatedCount++;
|
|
521
|
+
removedIdsTotal += invalidIds.length;
|
|
522
|
+
this.logger.info('清理白名单', `QQ(${bind.qqId})移除了${invalidIds.length}个无效的服务器ID: ${invalidIds.join(', ')}`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
// 生成清理报告
|
|
527
|
+
const invalidIdsArray = Array.from(invalidIdsFound);
|
|
528
|
+
let resultMessage = `白名单清理完成\n共处理${processedCount}条记录,更新${updatedCount}条记录\n移除了${removedIdsTotal}个无效的白名单条目`;
|
|
529
|
+
if (invalidIdsArray.length > 0) {
|
|
530
|
+
resultMessage += `\n\n发现的无效服务器ID:\n${invalidIdsArray.map(id => `• ${id}`).join('\n')}`;
|
|
531
|
+
}
|
|
532
|
+
this.logger.info('清理白名单', `成功: 主人QQ(${normalizedUserId})清理完成,处理${processedCount}条记录,更新${updatedCount}条记录,移除${removedIdsTotal}个无效条目`);
|
|
533
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(resultMessage)]);
|
|
534
|
+
}
|
|
535
|
+
catch (error) {
|
|
536
|
+
const normalizedUserId = this.deps.normalizeQQId(session.userId);
|
|
537
|
+
this.logger.error('清理白名单', `QQ(${normalizedUserId})清理白名单失败: ${error.message}`);
|
|
538
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(this.getFriendlyErrorMessage(error))]);
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* 批量将所有用户添加到服务器白名单
|
|
544
|
+
*/
|
|
545
|
+
registerAddAllCommand(parent) {
|
|
546
|
+
parent.subcommand('.addall <serverIdOrName:string>', '[管理员]将所有用户添加到指定服务器白名单')
|
|
547
|
+
.action(async ({ session }, serverIdOrName) => {
|
|
548
|
+
try {
|
|
549
|
+
const normalizedUserId = this.deps.normalizeQQId(session.userId);
|
|
550
|
+
// 检查是否为管理员
|
|
551
|
+
if (!await this.isAdmin(session.userId)) {
|
|
552
|
+
this.logger.warn('批量白名单', `权限不足: QQ(${normalizedUserId})不是管理员,无法执行批量添加白名单操作`);
|
|
553
|
+
return this.deps.sendMessage(session, [koishi_1.h.text('只有管理员才能执行批量添加白名单操作')]);
|
|
554
|
+
}
|
|
555
|
+
// 检查服务器名称或ID
|
|
556
|
+
if (!serverIdOrName) {
|
|
557
|
+
this.logger.warn('批量白名单', `QQ(${normalizedUserId})未提供服务器名称或ID`);
|
|
558
|
+
return this.deps.sendMessage(session, [koishi_1.h.text('请提供服务器名称或ID\n使用 mcid whitelist servers 查看可用服务器列表')]);
|
|
559
|
+
}
|
|
560
|
+
// 获取服务器配置
|
|
561
|
+
const server = this.getServerConfigByIdOrName(serverIdOrName);
|
|
562
|
+
if (!server) {
|
|
563
|
+
this.logger.warn('批量白名单', `QQ(${normalizedUserId})提供的服务器名称或ID"${serverIdOrName}"无效`);
|
|
564
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`未找到名称或ID为"${serverIdOrName}"的服务器\n使用 mcid whitelist servers 查看可用服务器列表`)]);
|
|
565
|
+
}
|
|
566
|
+
// 检查服务器是否启用
|
|
567
|
+
if (server.enabled === false) {
|
|
568
|
+
this.logger.warn('批量白名单', `QQ(${normalizedUserId})尝试为已停用的服务器"${server.name}"批量添加白名单`);
|
|
569
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`服务器"${server.name}"已停用,无法添加白名单`)]);
|
|
570
|
+
}
|
|
571
|
+
// 发送开始执行的通知
|
|
572
|
+
await this.deps.sendMessage(session, [koishi_1.h.text(`开始批量添加白名单到服务器"${server.name}",请稍候...`)]);
|
|
573
|
+
// 查询所有已绑定MC账号的用户
|
|
574
|
+
const allBinds = await this.repos.mcidbind.findAll();
|
|
575
|
+
// 过滤掉无效的绑定:没有用户名或UUID的记录
|
|
576
|
+
const validBinds = allBinds.filter(bind => (bind.mcUsername && bind.mcUsername.trim() !== '' && !bind.mcUsername.startsWith('_temp_')) ||
|
|
577
|
+
(bind.mcUuid && bind.mcUuid.trim() !== ''));
|
|
578
|
+
// 按绑定时间排序,早绑定的用户优先处理
|
|
579
|
+
validBinds.sort((a, b) => {
|
|
580
|
+
const timeA = a.lastModified ? new Date(a.lastModified).getTime() : 0;
|
|
581
|
+
const timeB = b.lastModified ? new Date(b.lastModified).getTime() : 0;
|
|
582
|
+
return timeA - timeB; // 升序排序,早绑定的在前
|
|
583
|
+
});
|
|
584
|
+
this.logger.info('批量白名单', `管理员QQ(${normalizedUserId})正在批量添加服务器"${server.name}"的白名单,共有${validBinds.length}条有效记录需要处理,已按绑定时间排序(早绑定优先)`);
|
|
585
|
+
// 统计信息
|
|
586
|
+
let successCount = 0;
|
|
587
|
+
let failCount = 0;
|
|
588
|
+
let skipCount = 0;
|
|
589
|
+
// 记录最后一次通知的进度百分比
|
|
590
|
+
let lastNotifiedProgress = 0;
|
|
591
|
+
// 使用队列处理,每个请求等待上一个完成后再继续
|
|
592
|
+
// 移除并发处理,改为顺序处理确保RCON命令按顺序执行
|
|
593
|
+
for (let i = 0; i < validBinds.length; i++) {
|
|
594
|
+
const bind = validBinds[i];
|
|
595
|
+
try {
|
|
596
|
+
// 跳过已经在白名单中的用户
|
|
597
|
+
if (this.isInServerWhitelist(bind, server.id)) {
|
|
598
|
+
skipCount++;
|
|
599
|
+
this.logger.debug('批量白名单', `跳过已在白名单中的用户QQ(${bind.qqId})的MC账号(${bind.mcUsername})`);
|
|
600
|
+
}
|
|
601
|
+
else {
|
|
602
|
+
// 添加错误阈值检查
|
|
603
|
+
const currentFailRate = failCount / (successCount + failCount + 1);
|
|
604
|
+
if (currentFailRate > 0.5 && (successCount + failCount) >= 5) {
|
|
605
|
+
this.logger.error('批量白名单', `失败率过高(${Math.round(currentFailRate * 100)}%),中止操作`);
|
|
606
|
+
await this.deps.sendMessage(session, [koishi_1.h.text(`⚠️ 批量添加白名单操作已中止: 失败率过高(${Math.round(currentFailRate * 100)}%),请检查服务器连接`)]);
|
|
607
|
+
break;
|
|
608
|
+
}
|
|
609
|
+
// 执行添加白名单操作,顺序执行确保每个命令等待上一个完成
|
|
610
|
+
const result = await this.addServerWhitelist(bind, server);
|
|
611
|
+
if (result) {
|
|
612
|
+
successCount++;
|
|
613
|
+
this.logger.debug('批量白名单', `成功添加用户QQ(${bind.qqId})的MC账号(${bind.mcUsername})到服务器"${server.name}"的白名单`);
|
|
614
|
+
}
|
|
615
|
+
else {
|
|
616
|
+
failCount++;
|
|
617
|
+
this.logger.error('批量白名单', `添加用户QQ(${bind.qqId})的MC账号(${bind.mcUsername})到服务器"${server.name}"的白名单失败`);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
catch (error) {
|
|
622
|
+
failCount++;
|
|
623
|
+
this.logger.error('批量白名单', `处理用户QQ(${bind.qqId})时出错: ${error.message}`);
|
|
624
|
+
// 如果错误指示操作已中止,退出循环
|
|
625
|
+
if (error.message.includes('失败率过高')) {
|
|
626
|
+
await this.deps.sendMessage(session, [koishi_1.h.text(`⚠️ 批量添加白名单操作已中止: ${error.message}`)]);
|
|
627
|
+
break;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
// 计算进度
|
|
631
|
+
const processedCount = i + 1;
|
|
632
|
+
const progress = Math.floor((processedCount / validBinds.length) * 100);
|
|
633
|
+
// 只有当进度增加了20%或以上,或者是首次或最后一次才发送通知
|
|
634
|
+
if (i === 0 || progress - lastNotifiedProgress >= 20 || i === validBinds.length - 1) {
|
|
635
|
+
await this.deps.sendMessage(session, [koishi_1.h.text(`批量添加白名单进度: ${progress}%,已处理${processedCount}/${validBinds.length}个用户\n成功: ${successCount} | 失败: ${failCount} | 跳过: ${skipCount}`)]);
|
|
636
|
+
lastNotifiedProgress = progress;
|
|
637
|
+
}
|
|
638
|
+
// 添加延迟确保RCON命令有足够的处理时间,避免过载
|
|
639
|
+
await new Promise(resolve => setTimeout(resolve, 1000)); // 每个请求间隔1秒
|
|
640
|
+
}
|
|
641
|
+
this.logger.info('批量白名单', `成功: 管理员QQ(${normalizedUserId})批量添加了服务器"${server.name}"的白名单,成功: ${successCount},失败: ${failCount},跳过: ${skipCount}`);
|
|
642
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(`批量添加服务器"${server.name}"白名单完成\n共处理${validBinds.length}个有效用户\n✅ 成功: ${successCount} 个\n❌ 失败: ${failCount} 个\n⏭️ 跳过(已在白名单): ${skipCount} 个\n\n如需查看详细日志,请查看服务器日志文件`)]);
|
|
643
|
+
}
|
|
644
|
+
catch (error) {
|
|
645
|
+
const normalizedUserId = this.deps.normalizeQQId(session.userId);
|
|
646
|
+
this.logger.error('批量白名单', `QQ(${normalizedUserId})批量添加白名单失败: ${error.message}`);
|
|
647
|
+
return this.deps.sendMessage(session, [koishi_1.h.text(this.getFriendlyErrorMessage(error))]);
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* 私有辅助方法:检查用户是否为管理员
|
|
653
|
+
*/
|
|
654
|
+
async isAdmin(userId) {
|
|
655
|
+
// 主人始终是管理员
|
|
656
|
+
const normalizedMasterId = this.deps.normalizeQQId(this.config.masterId);
|
|
657
|
+
const normalizedQQId = this.deps.normalizeQQId(userId);
|
|
658
|
+
if (normalizedQQId === normalizedMasterId)
|
|
659
|
+
return true;
|
|
660
|
+
// 查询MCIDBIND表中是否是管理员
|
|
661
|
+
try {
|
|
662
|
+
const bind = await this.deps.getBindInfo(normalizedQQId);
|
|
663
|
+
return bind && bind.isAdmin === true;
|
|
664
|
+
}
|
|
665
|
+
catch (error) {
|
|
666
|
+
this.logger.error('权限检查', `QQ(${normalizedQQId})的管理员状态查询失败: ${error.message}`);
|
|
667
|
+
return false;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* 私有辅助方法:检查是否为主人
|
|
672
|
+
*/
|
|
673
|
+
isMaster(qqId) {
|
|
674
|
+
const normalizedMasterId = this.deps.normalizeQQId(this.config.masterId);
|
|
675
|
+
const normalizedQQId = this.deps.normalizeQQId(qqId);
|
|
676
|
+
return normalizedQQId === normalizedMasterId;
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* 私有辅助方法:根据服务器ID或名称获取服务器配置
|
|
680
|
+
*/
|
|
681
|
+
getServerConfigByIdOrName(serverIdOrName) {
|
|
682
|
+
if (!this.config.servers || !Array.isArray(this.config.servers))
|
|
683
|
+
return null;
|
|
684
|
+
// 先尝试通过ID精确匹配
|
|
685
|
+
const serverById = this.getServerConfigById(serverIdOrName);
|
|
686
|
+
if (serverById)
|
|
687
|
+
return serverById;
|
|
688
|
+
// 如果ID未匹配到,尝试通过名称匹配
|
|
689
|
+
return this.getServerConfigByName(serverIdOrName);
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* 私有辅助方法:根据服务器ID获取服务器配置
|
|
693
|
+
*/
|
|
694
|
+
getServerConfigById(serverId) {
|
|
695
|
+
if (!this.config.servers || !Array.isArray(this.config.servers))
|
|
696
|
+
return null;
|
|
697
|
+
return this.config.servers.find(server => server.id === serverId && (server.enabled !== false)) || null;
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* 私有辅助方法:根据服务器名称获取服务器配置
|
|
701
|
+
*/
|
|
702
|
+
getServerConfigByName(serverName) {
|
|
703
|
+
if (!this.config.servers || !Array.isArray(this.config.servers))
|
|
704
|
+
return null;
|
|
705
|
+
// 过滤出启用的服务器
|
|
706
|
+
const enabledServers = this.config.servers.filter(server => server.enabled !== false);
|
|
707
|
+
// 尝试精确匹配
|
|
708
|
+
let server = enabledServers.find(server => server.name === serverName);
|
|
709
|
+
// 如果精确匹配失败,尝试模糊匹配
|
|
710
|
+
if (!server) {
|
|
711
|
+
const lowerServerName = serverName.toLowerCase().trim();
|
|
712
|
+
// 最小相似度阈值,低于此值的匹配结果将被忽略
|
|
713
|
+
const MIN_SIMILARITY = 0.6; // 60%的相似度
|
|
714
|
+
// 首先尝试包含关系匹配(A包含于B,或B包含于A)
|
|
715
|
+
const containsMatches = enabledServers.filter(server => server.name.toLowerCase().includes(lowerServerName) ||
|
|
716
|
+
lowerServerName.includes(server.name.toLowerCase()));
|
|
717
|
+
if (containsMatches.length === 1) {
|
|
718
|
+
// 如果只有一个匹配,验证相似度是否达到阈值
|
|
719
|
+
const similarity = this.similarityScore(containsMatches[0].name.toLowerCase(), lowerServerName);
|
|
720
|
+
if (similarity >= MIN_SIMILARITY) {
|
|
721
|
+
// 相似度达到阈值,返回匹配结果
|
|
722
|
+
server = containsMatches[0];
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
else if (containsMatches.length > 1) {
|
|
726
|
+
// 如果有多个匹配,计算相似度并选择最接近的一个
|
|
727
|
+
let bestServer = null;
|
|
728
|
+
let bestSimilarity = 0;
|
|
729
|
+
for (const candidate of containsMatches) {
|
|
730
|
+
const similarity = this.similarityScore(candidate.name.toLowerCase(), lowerServerName);
|
|
731
|
+
// 记录最佳匹配(相似度最高且达到阈值)
|
|
732
|
+
if (similarity > bestSimilarity && similarity >= MIN_SIMILARITY) {
|
|
733
|
+
bestSimilarity = similarity;
|
|
734
|
+
bestServer = candidate;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
server = bestServer;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
return server || null;
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* 私有辅助方法:计算两个字符串的相似度
|
|
744
|
+
*/
|
|
745
|
+
similarityScore(a, b) {
|
|
746
|
+
// 如果两个字符串相同,直接返回1
|
|
747
|
+
if (a === b)
|
|
748
|
+
return 1;
|
|
749
|
+
// 如果长度为0,返回0
|
|
750
|
+
if (a.length === 0 || b.length === 0)
|
|
751
|
+
return 0;
|
|
752
|
+
// 如果一个字符串完全包含另一个字符串,计算其占比
|
|
753
|
+
if (a.includes(b)) {
|
|
754
|
+
return b.length / a.length;
|
|
755
|
+
}
|
|
756
|
+
if (b.includes(a)) {
|
|
757
|
+
return a.length / b.length;
|
|
758
|
+
}
|
|
759
|
+
// 否则计算Levenshtein距离的相似度
|
|
760
|
+
const maxLength = Math.max(a.length, b.length);
|
|
761
|
+
const editDistance = this.levenshteinDistance(a, b);
|
|
762
|
+
return 1 - (editDistance / maxLength);
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* 私有辅助方法:计算Levenshtein距离
|
|
766
|
+
*/
|
|
767
|
+
levenshteinDistance(a, b) {
|
|
768
|
+
const matrix = [];
|
|
769
|
+
// 初始化矩阵
|
|
770
|
+
for (let i = 0; i <= b.length; i++) {
|
|
771
|
+
matrix[i] = [i];
|
|
772
|
+
}
|
|
773
|
+
for (let j = 0; j <= a.length; j++) {
|
|
774
|
+
matrix[0][j] = j;
|
|
775
|
+
}
|
|
776
|
+
// 填充矩阵
|
|
777
|
+
for (let i = 1; i <= b.length; i++) {
|
|
778
|
+
for (let j = 1; j <= a.length; j++) {
|
|
779
|
+
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
780
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
781
|
+
}
|
|
782
|
+
else {
|
|
783
|
+
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // 替换
|
|
784
|
+
matrix[i][j - 1] + 1, // 插入
|
|
785
|
+
matrix[i - 1][j] + 1 // 删除
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
return matrix[b.length][a.length];
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* 私有辅助方法:检查用户是否在特定服务器的白名单中
|
|
794
|
+
*/
|
|
795
|
+
isInServerWhitelist(mcBind, serverId) {
|
|
796
|
+
if (!mcBind || !mcBind.whitelist)
|
|
797
|
+
return false;
|
|
798
|
+
return mcBind.whitelist.includes(serverId);
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* 私有辅助方法:添加服务器白名单
|
|
802
|
+
* 注意:这是对 RconManager 的封装,实际执行逻辑在主文件中
|
|
803
|
+
*/
|
|
804
|
+
async addServerWhitelist(mcBind, server) {
|
|
805
|
+
try {
|
|
806
|
+
if (!mcBind || !mcBind.mcUsername) {
|
|
807
|
+
this.logger.warn('白名单', `尝试为未绑定MC账号的用户添加白名单`);
|
|
808
|
+
return false;
|
|
809
|
+
}
|
|
810
|
+
// 重新获取最新的用户绑定信息
|
|
811
|
+
const freshBind = await this.deps.getBindInfo(mcBind.qqId);
|
|
812
|
+
if (!freshBind || !freshBind.mcUsername) {
|
|
813
|
+
this.logger.warn('白名单', `用户QQ(${mcBind.qqId})可能在操作过程中解绑了MC账号`);
|
|
814
|
+
return false;
|
|
815
|
+
}
|
|
816
|
+
// 检查最新状态是否已在白名单中
|
|
817
|
+
if (freshBind.whitelist && freshBind.whitelist.includes(server.id)) {
|
|
818
|
+
this.logger.info('白名单', `用户QQ(${mcBind.qqId})已在服务器${server.name}的白名单中`);
|
|
819
|
+
return true;
|
|
820
|
+
}
|
|
821
|
+
// 判断使用用户名还是UUID
|
|
822
|
+
let mcid;
|
|
823
|
+
if (server.idType === 'uuid') {
|
|
824
|
+
if (!freshBind.mcUuid) {
|
|
825
|
+
this.logger.warn('白名单', `用户缺少UUID信息,无法添加白名单`);
|
|
826
|
+
return false;
|
|
827
|
+
}
|
|
828
|
+
const uuid = freshBind.mcUuid.trim();
|
|
829
|
+
mcid = uuid.replace(/-/g, '');
|
|
830
|
+
if (!/^[0-9a-f]{32}$/i.test(mcid)) {
|
|
831
|
+
this.logger.warn('白名单', `UUID格式无效: ${mcid},应为32位十六进制字符`);
|
|
832
|
+
return false;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
else {
|
|
836
|
+
mcid = freshBind.mcUsername;
|
|
837
|
+
}
|
|
838
|
+
this.logger.info('白名单', `为用户QQ(${freshBind.qqId})添加白名单,使用${server.idType === 'uuid' ? 'UUID' : '用户名'}: ${mcid}`);
|
|
839
|
+
// 使用 RconManager 执行命令
|
|
840
|
+
const command = this.safeCommandReplace(server.addCommand, mcid);
|
|
841
|
+
const response = await this.deps.rconManager.executeCommand(server, command);
|
|
842
|
+
// 判断是否成功
|
|
843
|
+
let success = false;
|
|
844
|
+
if (response.trim() === '') {
|
|
845
|
+
if (server.acceptEmptyResponse) {
|
|
846
|
+
this.logger.info('白名单', `收到空响应,根据配置将其视为成功`);
|
|
847
|
+
success = true;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
else {
|
|
851
|
+
const successKeywords = ['已', '成功', 'success', 'added', 'okay', 'done', 'completed', 'added to', 'whitelist has', 'whitelisted'];
|
|
852
|
+
const failureKeywords = ['失败', 'error', 'failed', 'not found', '不存在', 'cannot', 'unable', 'failure', 'exception', 'denied'];
|
|
853
|
+
const hasFailureKeyword = failureKeywords.some(keyword => response.toLowerCase().includes(keyword.toLowerCase()));
|
|
854
|
+
const hasSuccessKeyword = successKeywords.some(keyword => response.toLowerCase().includes(keyword.toLowerCase()));
|
|
855
|
+
if (!hasFailureKeyword && (hasSuccessKeyword || response.length > 0)) {
|
|
856
|
+
success = true;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
if (success) {
|
|
860
|
+
// 更新数据库
|
|
861
|
+
const currentBind = await this.deps.getBindInfo(freshBind.qqId);
|
|
862
|
+
if (currentBind) {
|
|
863
|
+
const whitelistSet = new Set(currentBind.whitelist || []);
|
|
864
|
+
whitelistSet.add(server.id);
|
|
865
|
+
await this.repos.mcidbind.update(freshBind.qqId, {
|
|
866
|
+
whitelist: Array.from(whitelistSet)
|
|
867
|
+
});
|
|
868
|
+
this.logger.info('白名单', `成功将QQ(${freshBind.qqId})添加到服务器${server.name}的白名单`);
|
|
869
|
+
}
|
|
870
|
+
return true;
|
|
871
|
+
}
|
|
872
|
+
else {
|
|
873
|
+
this.logger.warn('白名单', `添加白名单失败,服务器响应: ${response}`);
|
|
874
|
+
return false;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
catch (error) {
|
|
878
|
+
this.logger.error('白名单', `添加白名单失败: ${error.message}`);
|
|
879
|
+
return false;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
* 私有辅助方法:移除服务器白名单
|
|
884
|
+
*/
|
|
885
|
+
async removeServerWhitelist(mcBind, server) {
|
|
886
|
+
try {
|
|
887
|
+
if (!mcBind || !mcBind.mcUsername) {
|
|
888
|
+
this.logger.warn('白名单', `尝试为未绑定MC账号的用户移除白名单`);
|
|
889
|
+
return false;
|
|
890
|
+
}
|
|
891
|
+
// 重新获取最新的用户绑定信息
|
|
892
|
+
const freshBind = await this.deps.getBindInfo(mcBind.qqId);
|
|
893
|
+
if (!freshBind || !freshBind.mcUsername) {
|
|
894
|
+
this.logger.warn('白名单', `用户QQ(${mcBind.qqId})可能在操作过程中解绑了MC账号`);
|
|
895
|
+
return false;
|
|
896
|
+
}
|
|
897
|
+
// 检查最新状态是否在白名单中
|
|
898
|
+
if (!freshBind.whitelist || !freshBind.whitelist.includes(server.id)) {
|
|
899
|
+
this.logger.info('白名单', `用户QQ(${mcBind.qqId})不在服务器${server.name}的白名单中`);
|
|
900
|
+
return true; // 不在白名单中,无需移除,视为成功
|
|
901
|
+
}
|
|
902
|
+
// 判断使用用户名还是UUID
|
|
903
|
+
let mcid;
|
|
904
|
+
if (server.idType === 'uuid') {
|
|
905
|
+
if (!freshBind.mcUuid) {
|
|
906
|
+
this.logger.warn('白名单', `用户缺少UUID信息,无法移除白名单`);
|
|
907
|
+
return false;
|
|
908
|
+
}
|
|
909
|
+
const uuid = freshBind.mcUuid.trim();
|
|
910
|
+
mcid = uuid.replace(/-/g, '');
|
|
911
|
+
if (!/^[0-9a-f]{32}$/i.test(mcid)) {
|
|
912
|
+
this.logger.warn('白名单', `UUID格式无效: ${mcid},应为32位十六进制字符`);
|
|
913
|
+
return false;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
else {
|
|
917
|
+
mcid = freshBind.mcUsername;
|
|
918
|
+
}
|
|
919
|
+
this.logger.info('白名单', `为用户QQ(${freshBind.qqId})移除白名单,使用${server.idType === 'uuid' ? 'UUID' : '用户名'}: ${mcid}`);
|
|
920
|
+
// 使用 RconManager 执行命令
|
|
921
|
+
const command = this.safeCommandReplace(server.removeCommand, mcid);
|
|
922
|
+
const response = await this.deps.rconManager.executeCommand(server, command);
|
|
923
|
+
// 判断是否成功
|
|
924
|
+
let success = false;
|
|
925
|
+
if (response.trim() === '') {
|
|
926
|
+
if (server.acceptEmptyResponse) {
|
|
927
|
+
this.logger.info('白名单', `收到空响应,根据配置将其视为成功`);
|
|
928
|
+
success = true;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
else {
|
|
932
|
+
const successKeywords = ['移除', '已完成', '成功', 'success', 'removed', 'okay', 'done', 'completed', 'removePlayer', 'took', 'off'];
|
|
933
|
+
const failureKeywords = ['失败', '错误', 'error', 'failed', 'cannot', 'unable', 'failure', 'exception', 'denied'];
|
|
934
|
+
const notFoundKeywords = ['not found', '不存在', 'no player was removed', 'is not whitelisted', 'not in'];
|
|
935
|
+
const hasSuccessKeyword = successKeywords.some(keyword => response.toLowerCase().includes(keyword.toLowerCase()));
|
|
936
|
+
const hasFailureKeyword = failureKeywords.some(keyword => response.toLowerCase().includes(keyword.toLowerCase()));
|
|
937
|
+
const isNotExist = notFoundKeywords.some(keyword => response.toLowerCase().includes(keyword.toLowerCase()));
|
|
938
|
+
const notInLocal = !freshBind.whitelist || !freshBind.whitelist.includes(server.id);
|
|
939
|
+
if ((hasSuccessKeyword && !hasFailureKeyword) || (isNotExist && notInLocal)) {
|
|
940
|
+
success = true;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
if (success) {
|
|
944
|
+
// 更新数据库
|
|
945
|
+
const currentBind = await this.deps.getBindInfo(freshBind.qqId);
|
|
946
|
+
if (currentBind && currentBind.whitelist && currentBind.whitelist.includes(server.id)) {
|
|
947
|
+
currentBind.whitelist = currentBind.whitelist.filter(id => id !== server.id);
|
|
948
|
+
await this.repos.mcidbind.update(freshBind.qqId, {
|
|
949
|
+
whitelist: currentBind.whitelist
|
|
950
|
+
});
|
|
951
|
+
this.logger.info('白名单', `成功将QQ(${freshBind.qqId})从服务器${server.name}的白名单移除`);
|
|
952
|
+
}
|
|
953
|
+
return true;
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
this.logger.warn('白名单', `移除白名单失败,服务器响应: ${response}`);
|
|
957
|
+
return false;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
catch (error) {
|
|
961
|
+
this.logger.error('白名单', `移除白名单失败: ${error.message}`);
|
|
962
|
+
return false;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* 私有辅助方法:安全地替换命令模板
|
|
967
|
+
*/
|
|
968
|
+
safeCommandReplace(template, mcid) {
|
|
969
|
+
// 过滤可能导致命令注入的字符
|
|
970
|
+
const sanitizedMcid = mcid.replace(/[;&|"`'$\\]/g, '');
|
|
971
|
+
// 如果经过过滤后的mcid与原始mcid不同,记录警告
|
|
972
|
+
if (sanitizedMcid !== mcid) {
|
|
973
|
+
this.logger.warn('安全', `检测到潜在危险字符,已自动过滤: '${mcid}' -> '${sanitizedMcid}'`);
|
|
974
|
+
}
|
|
975
|
+
return template.replace(/\${MCID}/g, sanitizedMcid);
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* 私有辅助方法:获取友好的错误信息
|
|
979
|
+
*/
|
|
980
|
+
getFriendlyErrorMessage(error) {
|
|
981
|
+
const errorMsg = error instanceof Error ? error.message : error;
|
|
982
|
+
// Mojang API相关错误
|
|
983
|
+
if (errorMsg.includes('ECONNABORTED') || errorMsg.includes('timeout')) {
|
|
984
|
+
return '无法连接到Mojang服务器,请稍后再试';
|
|
985
|
+
}
|
|
986
|
+
if (errorMsg.includes('404')) {
|
|
987
|
+
return '该Minecraft用户名不存在';
|
|
988
|
+
}
|
|
989
|
+
if (errorMsg.includes('network') || errorMsg.includes('connect')) {
|
|
990
|
+
return '网络连接异常,请稍后再试';
|
|
991
|
+
}
|
|
992
|
+
// 数据库相关错误
|
|
993
|
+
if (errorMsg.includes('unique') || errorMsg.includes('duplicate')) {
|
|
994
|
+
return '该Minecraft用户名已被其他用户绑定';
|
|
995
|
+
}
|
|
996
|
+
// RCON相关错误
|
|
997
|
+
if (errorMsg.includes('RCON') || errorMsg.includes('服务器')) {
|
|
998
|
+
if (errorMsg.includes('authentication') || errorMsg.includes('auth') || errorMsg.includes('认证')) {
|
|
999
|
+
return 'RCON认证失败,服务器拒绝访问,请联系管理员检查密码';
|
|
1000
|
+
}
|
|
1001
|
+
if (errorMsg.includes('ECONNREFUSED') || errorMsg.includes('ETIMEDOUT') || errorMsg.includes('无法连接')) {
|
|
1002
|
+
return '无法连接到游戏服务器,请确认服务器是否在线或联系管理员';
|
|
1003
|
+
}
|
|
1004
|
+
if (errorMsg.includes('command') || errorMsg.includes('执行命令')) {
|
|
1005
|
+
return '服务器命令执行失败,请稍后再试';
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
return errorMsg;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
exports.WhitelistHandler = WhitelistHandler;
|